Showing posts with label Wildfly. Show all posts
Showing posts with label Wildfly. Show all posts

July 20, 2015

Multitenancy Part 1 - Custom Login Module & Bcrypt Password Hashing on WildFly 9

Quick note on multi-tenancy

This example is for a shared schema approach, which is a common requirement in many SaaS applications. Hibernate currently supports separate database and separate schema, but not shared schema. There are plans for shared schema in Hibernate 5.  My next post will show you how to use this custom login module/principal to support shared schema multi-tenancy in your Java EE 7 application.

For an excellent overview on multitenacy, check this article.

Quick note on password hashing

The default options in WildFly for storing passwords (MD5, SHA-512 etc) are great for demo's or prototypes, but are not suitable for a live environment. For a good introduction to password hashing see here.

What is covered in this post

How to create a custom principal
How to create custom login module
How to apply non-default hashing/password algorithm (BCrypt in this example)
How to modify your custom principal for a multi-tenancy application (shared schema approach)

Works with WildFly 9 (picketbox 4.9.2.Final), minor modification is required for WildFly 8 (pickbox <= 4.0.21.Final)

Why a custom principal?

In addition to the username, I need to store a reference to the userId and the tenantId. I want to have the option of looking up a JPA User by their userId, not their username. Also, because this is for a multi-tenant application, I want to be able to quickly access the tenantId (for example when applying a filter to queries).

Why a custom login module?

Two reasons. First I need to set the tenantId and userId on the identity object (principal).
Second, I want to apply a strong hashing algorithm and a per-user salt. In this example I use the BCrypt hashing function.

Now to the code...

First add the maven dependencies:
<!-- provides security implementation for WildFly -->
<dependency>
    <groupId>org.picketbox</groupId>
    <artifactId>picketbox</artifactId>
    <version>4.9.2.Final</version>
    <scope>provided</scope>
</dependency>
<!-- Java BCrypt library -->
<dependency>
    <groupId>de.svenkubiak</groupId>
    <artifactId>jBCrypt</artifactId>
    <version>0.4</version>
</dependency>
<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>jta</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.jboss.logging</groupId>
    <artifactId>jboss-logging</artifactId>
    <version>3.3.0.Final</version>
    <scope>provided</scope>
</dependency>

Create the custom principal

In this example we will be extending org.jboss.security.SimplePrincipal with our own implementation, which will store a reference to the tenantId and userId in addition to the username.
public class DatabasePrincipal extends SimplePrincipal {

    private Long userId;
    private Integer tenantId;
    
    //required when creating principal See AbstractServerLoginModule.createIdentity();
    public DatabasePrincipal(String userName) {
        super(userName);
    }

    public Long getUserId() {
        return userId;
    }

    public Integer getTenantId() {
        return tenantId;
    }

    void setUserId(long userId) {
        this.userId = userId;
    }

    void setTenantId(int tenantId) {
        this.tenantId = tenantId;
    }
}

Create the custom database login module

We will extending DatabaseServerLoginModule and overriding validatePassword() so that we can use jBCrypt to check the raw password against the hashed password. To learn how to generate the hash in the first place you can check the jBCrypt docs. We also need to override the getUsersPassword() method as we need to get the tenantId and userId from PreparedStatement and then set them on our DatabasePrincipal.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.login.LoginException;
import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.Transaction;

import org.jboss.logging.Logger;
import org.jboss.security.PicketBoxMessages;
import org.jboss.security.auth.spi.DatabaseServerLoginModule;

public class MultitenantDatabaseServerLoginModule extends DatabaseServerLoginModule {

    private Logger log = Logger.getLogger(getClass());
 
    @Override
    protected boolean validatePassword(String enteredPassword, String encrypted) {
        
        if (enteredPassword == null || encrypted == null) {
            return false;
        }

        return BCrypt.checkpw(enteredPassword, encrypted)) {
    }

    @Override
    protected String getUsersPassword() throws LoginException {
        
        boolean trace = log.isTraceEnabled();
        String username = getUsername();
        String password = null;
        ResultSet rs = null;

        Transaction tx = null;
        if (suspendResume) {
            // tx = TransactionDemarcationSupport.suspendAnyTransaction();
            try {
                if (tm == null)
                    throw PicketBoxMessages.MESSAGES.invalidNullTransactionManager();
                tx = tm.suspend();
            } catch (SystemException e) {
                throw new RuntimeException(e);
            }
        }

        try {

            InitialContext ctx = new InitialContext();
            DataSource dataSource = (DataSource) ctx.lookup(dsJndiName);

            // Get the password
            if (trace) {
                log.trace("Excuting query: " + principalsQuery + ", with username: " + username);
            }
            try (Connection connection = dataSource.getConnection();
                    PreparedStatement statement = connection.prepareStatement(principalsQuery)) {

                statement.setString(1, username);
                rs = statement.executeQuery();

                if (rs.next() == false) {
                    if (trace) {
                        log.trace("Query returned no matches from db");
                    }
                    throw PicketBoxMessages.MESSAGES.noMatchingUsernameFoundInPrincipals();
                }

                Integer userId = rs.getInt(1);
                Integer tenantId = rs.getInt(2);
                password = rs.getString(3);

                //Set the tenant and user properties on the custom principal
                //there maybe a better place to do this, but this is the only place I can see it working without having to hit the database with another query. 
                DatabasePrincipal principle = (DatabasePrincipal) getIdentity();
                principle.setTenantId(tenantId);
                principle.setUserId(userId);

                if (trace) {
                    log.trace("Obtained user password");
                }

            } catch (SQLException ex) {
             LoginException le = new LoginException(PicketBoxMessages.MESSAGES.failedToProcessQueryMessage());
                le.initCause(ex.getCause());
                log.error(ex);
                throw le;
            } finally {
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException e) {
                    }
                }
            }

        } catch (NamingException ex) {
            LoginException le = new LoginException(PicketBoxMessages.MESSAGES.failedToLookupDataSourceMessage(dsJndiName));
            le.initCause(ex);
            log.error(ex);
            throw le;
        } finally {
            if (suspendResume) {
                // TransactionDemarcationSupport.resumeAnyTransaction(tx);
                try {
                    tm.resume(tx);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                if (log.isTraceEnabled())
                    log.trace("resumeAnyTransaction");
            }
        }
        return password;
    }
}

Configure the application

We now need to tell our application to use the new security domain. For Servlets (and FORM based authentication) you will need to add a security domain to the jboss-web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <security-domain>multitenantdomain</security-domain>
</jboss-web>

To use declarative security in your EJB's you will need to add the security domain to your jboss-ejb3.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<jboss:jboss
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:s="urn:security:1.1"
        version="3.1" impl-version="2.0">
 
    <assembly-descriptor>
        <s:security>
            <ejb-name>*</ejb-name>
            <s:security-domain>multitenantdomain</s:security-domain>
        </s:security>
    </assembly-descriptor>
</jboss:jboss>

And to use the security domain in your EJB, use the org.jboss.ejb3.annotation.SecurityDomain annotation:
@Stateless
@SecurityDomain("other")
public class MyEJB {

}

Configure WildFly

Lastly we need to tell WildFly which login module to use, and which principal implementation we want it to instantiate. We also need to specify our query (returning user_id and tenant_id).
<security-domain name="multitenantdomain" cache-type="default">
    <authentication>
        <login-module code="com.ritchie.security.MultitenantDatabaseServerLoginModule" flag="required">
            <module-option name="dsJndiName" value="java:jboss/datasources/MultitenantDS"/>
            <module-option name="principalsQuery" value="select user_id, tenant_id, password from User where username=?"/>
            <module-option name="rolesQuery" value="select Role, 'Roles' from User where Username=?"/>
            <module-option name="password-stacking" value="useFirstPass"/>
            <module-option name="principalClass" value="com.ritchie.security.DatabasePrincipal"/>
        </login-module>
    </authentication>
</security-domain>

And... for the sake of completeness

Here is a simple login page and web.xml configuration
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/access-denied.html</form-error-page>
        </form-login-config>
    </login-config>
    <security-constraint>
        <display-name>Open Content</display-name>
        <web-resource-collection>
            <web-resource-name>Unrestricted Content</web-resource-name>
            <url-pattern>/login.xhtml</url-pattern>
        </web-resource-collection>
    </security-constraint>
    <security-constraint>
        <display-name>Access Constraint</display-name>
 <web-resource-collection>
            <web-resource-name>Site Access Constraint</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    </security-constraint>
    <security-role>
        <role-name>administrator</role-name>
    </security-role>
</web-app>
index.html
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Login Page</title>
   </head>
   <body>
      <form method="post" action="j_security_check">
         <label for="username">Username:</label>
         <input id="username" required="required" type="text" name="j_username"/>
         <label for="password">Password:</label>
         <input id="password" required="required" type="password" name="j_password"/>
         <button type="submit">Login</button>
      </form>
   </body>
</html>

In the next post we will build on this example and create a CrudService that will apply a filter to queries to ensure data isolation between tenants.


Ref:
https://msdn.microsoft.com/en-us/library/aa479086.aspx
https://docs.jboss.org/author/display/WFLY8/Authentication+Modules
https://docs.jboss.org/author/display/WFLY8/Securing+EJBs
https://dzone.com/articles/creating-custom-login-modules
http://throwingfire.com/storing-passwords-securely/#notpasswordhashes
http://www.mindrot.org/projects/jBCrypt/

June 26, 2015

Configure SSL on WildFly 8 - Self Signed Certificate

Create a self-signed certificate inside the $JBOSS_HOME/standalone/configuration/ directory:
keytool -genkeypair -alias serverkey -keyalg RSA -keysize 2048 -validity 365 -keystore keystore.jks -keypass mypassword -storepass mypassword -dname "CN=Server Administrator,O=My Organization,C=ZA"
Add the security realm to the management section:
/core-service=management/security-realm=SSLRealm/:add()

Configure the new realm:
/core-service=management/security-realm=SSLRealm/server-identity=ssl/:add(keystore-path=keystore.jks, keystore-relative-to=jboss.server.config.dir, keystore-password=mypassword, alias=serverkey, key-password=mypassword)

Add the https-listener to the undertow configuration:
/subsystem=undertow/server=default-server/https-listener=https/:add(socket-binding=https, security-realm=SSLRealm)

This adds the following to your standalone.xml
<security-realm name="SSLRealm">
    <server-identities>
        <ssl>
            <keystore path="keystore.jks" relative-to="jboss.server.config.dir" keystore-password="mypassword" alias="serverkey" key-password="mypassword"/>
        </ssl>
    </server-identities>
</security-realm>
And the following is added to your undertow subsystem:
<https-listener name="https" socket-binding="https" security-realm="SSLRealm"/>

You should now be able to access your application on https://localhost:8443

March 11, 2015

Inject external properties using CDI, Java and WildFly

Often you need to be able to configure different runtime properties based on environment.  Using the configuration below, you can have a different property file on each server (dev, production, test), each defining their own values.

How it works

  1. The location of your property file is found by looking at a system property configured in the WildFly configuration file. This allows you to change the location of the property file, without having to recompile/redeploy the application.
  2. The property file is loaded and the values are stored in a HashMap inside a @Singleton session bean
  3. The properties are then injected into your CDI beans, making them accessible to your application code. This is achieved by creating a CDI Qualifier and producer method.

How its done

1. Create and populate a properties file inside the WildFly configuration folder
$ echo 'docs.dir=/var/documents' >> .standalone/configuration/application.properties

 2. Add a system property to the WildFly configuration file.
$ ./bin/jboss-cli.sh --connect
[standalone@localhost:9990 /] /system-property=application.properties:add(value=${jboss.server.config.dir}/application.properties)

This will add the following to your server configuration file (standalone.xml or domain.xml):
<system-properties>
    <property name="application.properties" value="${jboss.server.config.dir}/application.properties"/>
</system-properties>

3. Create the singleton session bean that loads and stores the application wide properties
package com.ritchie.chris.properties;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;

@Singleton
public class PropertyFileResolver {
     
    private Map<String, String> properties = new HashMap<>();
     
    @PostConstruct
    private void init() throws IOException {
         
        //matches the property name as defined in the system-properties element in WildFly
        String propertyFile = System.getProperty("application.properties");
        File file = new File(propertyFile);
        Properties properties = new Properties();
         
        try {
            properties.load(new FileInputStream(file));
        } catch (IOException e) {
            System.out.println("Unable to load properties file" + e);
        }
         
        HashMap hashMap = new HashMap<>(properties);
        this.properties.putAll(hashMap);
    }
 
    public String getProperty(String key) {
        return properties.get(key);
    }
}

4. Create the CDI Qualifier. We will use this annotation on the Java variables we wish to inject into.
package com.ritchie.chris.properties;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR })
public @interface ApplicationProperty {

    // no default meaning a value is mandatory
    @Nonbinding
    String name();
}

5. Create the producer method; this generates the object to be injected
package com.ritchie.chris.properties;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;

public class ApplicaitonPropertyProducer {

    @Inject
    private PropertyFileResolver fileResolver;

    @Produces
    @ApplicationProperty(name = "")
    public String getPropertyAsString(InjectionPoint injectionPoint) {
        
        String propertyName = injectionPoint.getAnnotated().getAnnotation(ApplicationProperty.class).name();
        String value = fileResolver.getProperty(propertyName);
        
        if (value == null || propertyName.trim().length() == 0) {
            throw new IllegalArgumentException("No property found with name " + value);
        }
        return value;
    }
    
    @Produces
    @ApplicationProperty(name="")
    public Integer getPropertyAsInteger(InjectionPoint injectionPoint) {
        
        String value = getPropertyAsString(injectionPoint);
        return value == null ? null : Integer.valueOf(value);
    }
}

6. Lastly inject the property into one of your CDI beans
package com.ritchie.chris.properties;

import javax.ejb.Stateless;
import javax.inject.Inject;

@Stateless
public class MySimpleEJB {

    @Inject
    @ApplicationProperty(name = "docs.dir")
    private String myProperty;
    
    public String getProperty() {
        return myProperty;
    }
}

Source code can be found on GitHub



February 27, 2015

Configure WildFly, Apache and websocket connections on Ubuntu 14.04

This tutorial assumes that you have already installed WildFly and you want to configure Apache as a proxy in front of WildFly, and you want to allow websocket connections. For a detailed guide on installing and configuring WildFly, see this post.

In this guide are going to install and configure Apache, mod_proxy and proxy_wstunnel. proxy_wstunnel is required if you want successfully connect to WildFly via websockets (thru Apache). Any attempt to connect via websockets without proxy_wstunnel will fail as the HTTP Upgrade headers will be removed from your request.

Apache install

First install Apache and the required mods:
sudo apt-get install apache2
sudo apt-get install libapache2-mod-proxy-html
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo /etc/init.d/apache2 restart

Apache configuration

Now configure your VirtualHost. For simplicity we are going to update the 000-default.conf file. In this example the context root of the application is app. Update yours as needed.
vim /etc/apache2/sites-available/000-default.conf

These two lines are required to proxy your main http connections
ProxyPass         /app  http://localhost:8080/pss
ProxyPassReverse  /app  http://localhost:8080/pss

These two lines will proxy your websocket connections
ProxyPass         /app/ws/  ws://localhost:8080/app/ws/
ProxyPassReverse  /app/ws/  ws://localhost:8080/app/ws/

Here is the full VirtualHost file, with the mod_proxy and proxy_wstunnel configuration highlighted:
<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/example.com

    ProxyPass         /app  http://localhost:8080/pss
    ProxyPassReverse  /app  http://localhost:8080/pss
    ProxyPass         /app/ws/  ws://localhost:8080/app/ws/
    ProxyPassReverse  /app/ws/  ws://localhost:8080/app/ws/

    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
Reload Apache for the changes to take effect
sudo /etc/init.d/apache2 reload

Java configuration

Make sure that the value you pass into your @ServerEndPoint annotation matches that in your Apache VirtualHost configuration.
@ServerEndpoint("/ws")
public class WebSocketEndpoint {
 
    private final Logger logger = Logger.getLogger(this.getClass().getName());
 
    @OnOpen
    public void onConnectionOpen(Session session) {
        logger.info("Connection opened");
    }
 
    @OnMessage
    public String onMessage(String message) {
        return "Message received";
    }
 
    @OnClose
    public void onConnectionClose(Session session) {
        logger.info("Connection closed");
    }
}

WildFly configuration

Make sure that you allow connections to your public interface from localhost (127.0.0.1) only. While this is not mandatory, leaving it open will allow connections to circumvent Apache.
<interfaces>
    <interface name="management">
        <inet-address value="0.0.0.0"/>
    </interface>
    <interface name="public">
        <inet-address value="${jboss.bind.address:127.0.0.1}"/>
    </interface>
    <interface name="unsecure">
        <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/>
    </interface>
</interfaces>

In WildFly websockets work out of the box, so no other configuration required. Here is the default undertow configuration, with the relevant parts highlighted.
<subsystem xmlns="urn:jboss:domain:undertow:1.2">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http"/>
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <filter-ref name="server-header"/>
            <filter-ref name="x-powered-by-header"/>
        </host>
    </server>
    <servlet-container name="default">
        <jsp-config/>
        <websockets/>
    </servlet-container>
</subsystem>
You should now be able to deploy your websocket applications to WildFly and access them via Apache.

February 17, 2015

Installing WildFly on Ubuntu 14.04 cloud server

This post covers the main aspects of installing WildFly on a fresh cloud Ubuntu server (or any clean install). This tutorial shows how WildFly can be configured to be accessed directly. If you want to put WildFly behind Apache using mod_proxy, see this post.

Topics covered: 


Adding swap to a new cloud instance 
  • Checking for swap
  • Creating swap
  • Changing swappiness 
Updating the server using apt-get 

Installing Java
  • Downloading the JDK to the server
  • Installing the JDK
  • Setting the default JDK
Installing WildFly
  • Downloading WildFly
  • Creating the wildfly user
  • Installing the init.d scripts
  • Starting WildFly as a service
Configuring WildFly
  • Open public interface to all IP's
  • Open the management interface to all IP's (optional)
  • Remove the welcome content (optional)

Adding swap to a new cloud instance  

Swap is an area on your hard drive that can store data when your RAM is full. First we need to check to see if a swap area is configured:
sudo swapon -s
If you get the headers back only, you have no swap space:

Now lets create a 4 gig swap:
sudo fallocate -l 4G /swapfile
Verify that is has been created and is the correct size
ls -lh /swapfile 
You should see something like this:

Now change the folder permissions:
sudo chmod 600 /swapfile
Set up swap
sudo mkswap /swapfile
You will should see the output below.


Now enable swap
sudo swapon /swapfile
Lets check to see if we have swap space
sudo swapon -s
We should get the following output:

To make the changes permanent you need to update the fstab file
sudo echo '/swapfile   none    swap    sw    0   0' >> /etc/fstab

Update swappiness

Swappiness can be configured between 0 and 100. The nearer to 0 the more data will be put into the RAM rather than the swap.

To view the current swappiness:
cat /proc/sys/vm/swappiness
To change the swapiness to 10:
sudo echo 'vm.swappiness=10' >> /etc/sysctl.conf
This only takes effect on reboot, so also run this command to effect this change immediately
sudo sysctl vm.swappiness=10

Updating the server using apt-get 

If you have not already updated your new server, do so now:
sudo apt-get update
sudo apt-get upgrade

Installing Java

Personally I like to install the Oracle JDK rather than OpenJDK. As you need to accept the Oracle licence before downloading, you will need to browse to the Java download page using your browser. Agree to the terms, and then click on download. As soon as it starts, pause it, and copy the download link.
Go to your server and use wget to download the file using the download link you just copied:
wget -c http://download.oracle.com/otn-pub/java/jdk/8u31-b13/jdk-8u31-linux-x64.tar.gz?AuthParam=1423681612_d8066e1256e66a7a4895ad467fc7cd07
When is has finished downloading, extract it to the /opt/java folder (or any other folder of your choosing)
mkdir /opt/java
tar -xvzf jdk-8u31-linux-x64.tar.gz -C /opt/java
Now add the following to the end of /etc/environment:
JAVA_HOME="/opt/java/jdk1.8.0_31"
PATH="$JAVA_HOME/bin:$PATH"
Now source the file to load the new $PATH and $JAVA_HOME properties
. /etc/environment

Installing WildFly

First install WildFly by downloading and extracting it to the /opt directory
cd /opt
wget -c http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.tar.gz
tar -xzvf wildfly-8.2.0.Final.tar.gz

Create the wildfly user and group

addgroup wildfly
useradd -g wildfly wildfly
Change the ownership of the wildfly folder recursively:
chown -R wildfly:wildfly /opt/wildfly-8.2.0.Final/ 
Create a symbolic link so that if you change WildFly versions, you don't have to update any other configuration:
ln -s wildfly-8.2.0.Final /opt/wildfly

Installing the init.d scripts

To easiest way to start and stop WildFly is to use a startup script. Copy and paste the init.d script within the WildFly install to the /etc/init.d/ folder, change the permissions, and make it executable:
cp /opt/wildfly/bin/init.d/wildfly-init-debian.sh /etc/init.d/wildfly
sudo chown root:root /etc/init.d/wildfly
sudo chmod ug+x /etc/init.d/wildfly
To start/stop WildFly you will simply run the commands
sudo /etc/init.d/wildfly start
sudo /etc/init.d/wildfly stop

Starting WildFly as a service

To enable WildFly to start automatically when the server starts, you need to add it to the linux run-levels:
sudo update-rc.d wildfly defaults 
You should see the following output:

Configuring WildFly - open the public interface to all IP's

To access WildFly from an IP other than 127.0.0.1 (localhost) you will need to update the bind address for the public interface. Update this:
<interface name="public">
    <inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
to this:
<interface name="public">
    <any-address/>
</interface>
You will now be able to access WildFly from any IP using port 8080


Open the management interface to all IP's (optional) 

If you want to access the management console (on port 9990), you will need to update the bind address as you did for the public interface:
<interface name="management">
    <any-address/>
</interface>
You will now be able to access the management interface on port 9990 from any computer.

Remove the welcome content (optional)

If you are deploying your application to the context root, you will need to remove the default welcome content from the WildFly configuration. Remove the lines highlighted in bold from the undertow subsystem in your standalone.xml file
<server name="default-server">
    <http-listener name="default" socket-binding="http"/>
    <host name="default-host" alias="localhost">
        <location name="/" handler="welcome-content"/>
        <filter-ref name="server-header"/>
        <filter-ref name="x-powered-by-header"/>
    </host>
</server>
<handlers>
    <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>

You will now be able to deploy your application to WildFly and view it on your_ip:8080. Make sure you configure your jboss-web.xml and set the context root to /.
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <context-root>/</context-root>
</jboss-web>
Enjoy :)

July 17, 2014

Save Session State Between Redeploys - Developing on WildFly

When developing, it is often convenient to save session state between redeploys or server restarts. To enable this feature in WildFly 8 you need to add the persistent-sessions element to your configuration file (within the undertow subsystem).

<servlet-container name="default">
    <persistent-sessions path="session" relative-to="jboss.server.temp.dir"/>
    <jsp-config/>
</servlet-container>
By specifying the relative-to attribute, the session will only be persistent across redeploys and not across server restarts.

This feature works in WildFly 8.2.0.CR1 and greater.

You can also achieve session passivation, when you are using a non-ha profile, by adding <distributable/> to your web.xml (for those using WildFly 8.1.0 or less).

April 22, 2014

How to use Java 8 with WildFly 8 and Eclipse

Prerequisites:

1. Download and install Java 8
2. Download and install WildFly 8
4. Download and install Eclipse Luna (4.4) (or Kepler 4.3 patched for Java 8)

Configure WildFlys VM args

Before starting WildFly, update your standalone.conf, or domain.conf by replacing the following JVM argument:
-XX:MaxPermSize=256m
with:
-XX:MaxMetaspaceSize=256m

The removal of the MaxPermSize property will prevent VM warnings from showing in WildFlys startup logs.

The -XX:PermSize and -XX:MaxPermSize VM arguments are now redundant as PermGen has been replaced in Java 8 with Metaspace. The new VM arguments are -XX:MetaspaceSize and -XX:MaxMetaspaceSize.
Note that the Metaspace data will sit in your computers native memory. For a rundown on the differences between PermGen and Metaspace, check out this blog.

Installing JBoss Tools

In Eclipse Luna (4.4), go to Help > Eclipse Marketplace and type 'JBoss Tools', and click go.  Make sure that you select and install the version that matches your Eclipse install. In this example it is JBoss Tools (Luna) 4.2.0.Beta1.



Click install.

On the next screen you can select which components of JBoss Tools you want to install. To install just the server adapter, select 'JBossAS Tools'. Agree to the terms and click OK. Restart Eclipse when you are given the option to do so.

Now choose File > New > Server. Expand the 'JBoss Community' node and select the option 'WildFly 8'.



Click Next, and Next again

Make sure you select your installed Java 8 JRE, and that you point the home directory to that of your WildFly root directory (As shown below). Click finish.



Finally, in your servers view (Window > Show View > Servers), Select the WildFly Server, right click and select start. All being well, WildFly should now start up.


Finally to configure your WildFly server settings, double click on the WildFly server in your servers view. The screen above should be displayed, allowing you to configure your server/deployment properties.

October 10, 2013

Simple Managed Thread Factory Example in Wildfly

In this example we are going to use the ManagedThreadFactory (part of Java EE7 Concurrency Utils) to create and run a background task. The advantage of this, rather than using java.lang.Thread, is that your new thread will have access to the other Java EE services. Using the ManagedThreadFactory ensures your threads are created, and managed, by the container.

Example

Like previous examples, we need a Runnable task which will define what work is to be done in the background.

public class ReportTask implements Runnable {

    Logger logger = Logger.getLogger(getClass().getSimpleName());

    public void run() {
        logger.log(Level.INFO, "New thread running...");
        try {
            //do your background task
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            logger.log(Level.SEVERE, "Thread interrupted", e);
        }
    }
}

To get a container managed thread, we simply ask the ManagedThreadFactory for a new thread, and pass it our Runnable instance.  To start the thread we call start().

@Stateless
public class ReportBean {
 
    @Resource(lookup="java:jboss/ee/concurrency/factory/MyManagedThreadFactory")
    private ManagedThreadFactory threadFactory;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Thread thread = threadFactory.newThread(reportTask);
        thread.start();
    }
}

We now need to configure our ManagedThreadFactory within Wildfly. This snippet is taken from the ee subsystem configuration in standalone.xml. The 'lookup' attribute of the @Resource annotation maps to 'jndi-name' attribute within the <managed-thread-factory> tag.

<subsystem xmlns="urn:jboss:domain:ee:2.0">
    ...
    <managed-thread-factories>
        <managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
        <managed-thread-factory name="myManagedThreadFactory" jndi-name="java:jboss/ee/concurrency/factory/MyManagedThreadFactory" context-service="default" priority="1"/>
    </managed-thread-factories>
    ...
</subsystem>

Below is the full list of attributes you can use to configure your managed-thread-factory in Wildfly.
  • name - This is the name of the resource. This attribute is manditory.
  • jndi-name - The JNDI name for this resource. This attribute is manditory
  • context-service - The context service to use, if not supplied, the default context service is used.
  • priority - The priority that the thread should have, from 1 to 10 inclusive. Default is 5. 

Using the Command Line Interface (CLI)

To create your ManagedThreadFactory using CLI, go to your terminal and connect to your server by running the following command, swapping out wildfly for your WildFly root directory:
$ wildfly/bin/jboss-cli.sh --connect
Now create the ManagedThreadFactory and set its properties by using the add command, passing through the required property-value pairs.
[standalone@localhost:9990 /] /subsystem=ee/managed-thread-factory=myManagedThreadFactory:add(priority=1,context-service=default,jndi-name=java:jboss/ee/concurrency/factory/MyManagedThreadFactory)
If you want to modify any of these properties use the write-attribute command, passing though the name of the attribute and the new value:
[standalone@localhost:9990 /] /subsystem=ee/managed-thread-factory=myManagedThreadFactory:write-attribute(name=priority,value=3)
Finally reload the server to make your changes avaliable:
[standalone@localhost:9990 /] /:reload

The Admin Console

To view your thread factory in the Wildfly Admin console, navigate to Runtime > JNDI View > java:jboss > ee > concurrent.  Here, you can see all the concurrent resources including your newly configured resource.


Note: Using the JNDI prefix of java:jboss/ee/concurrency/factory ensures that the resource shows under concurrency/factory list in the Wildfly admin console.


September 26, 2013

How to Configure Scheduled Tasks in Wildfly

This example shows you how to create a scheduled concurrent task that runs every hour, using the Concurrency Utils API, and how to configure the properties of a ManagedScheduledExecutorService within Wildfly.

Example


Firstly, lets create the Runnable task which will define what work is to be done in the background thread.

public class ReportTask implements Runnable {
 
    public void run() {
        try {
            //do your background task
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            //handle execption
        }
    }
}

Now we schedule the executor to run its first execution immediately, and every hour thereafter. This executor will continue to run until you either terminate it, or until an exception it thrown by the task. We call the scheduledAtFixedRate() method, passing through our runnable task, along with the properties defining our schedule, i.e. the delay, the frequency and time unit.

@Stateless
public class ReportBean {
 
    @Resource(lookup="java:jboss/ee/concurrency/scheduler/MyScheduledExectutorService")
    private ManagedScheduledExecutorService executorService;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        executorService.scheduleAtFixedRate(reportTask, 0L, 1L, TimeUnit.HOURS);
    }
}

Lastly we need to configure our ManagedScheduledExecutorService in Wildfly.  The 'lookup' attribute of the @Resource annotation maps to 'jndi-name' attribute within the <managed-scheduled-executor-service> tag.

<subsystem xmlns="urn:jboss:domain:ee:2.0">
            <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
            <jboss-descriptor-property-replacement>true</jboss-descriptor-property-replacement>
            <concurrent>
                <context-services>
                    <context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
                </context-services>
                <managed-thread-factories>
                    <managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
                </managed-thread-factories>
                <managed-executor-services>
                    <managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" core-threads="5" max-threads="25" keepalive-time="5000"/>
                </managed-executor-services>
                <managed-scheduled-executor-services>
                    <managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" core-threads="2" keepalive-time="3000"/>
                    <managed-scheduled-executor-service name="myScheduledExecutorService" jndi-name="java:jboss/ee/concurrency/scheduler/MyScheduledExectutorService" hung-task-threshold="50000" core-threads="4" keepalive-time="5000" reject-policy="RETRY_ABORT"/>
                </managed-scheduled-executor-services>
            </concurrent>
            <default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" jms-connection-factory="java:jboss/DefaultJMSConnectionFactory" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
</subsystem>

Note: If we were not to specify a any lookup or name attribute in the @Resource annotation, Wildfly would inject the default execution service.


Below is the full list of attributes you can use to configure your managed-scheduled-executor-service in Wildfly.
  • name - This is the name of the resource. This attribute is manditory.
  • jndi-name - The JNDI name for this resource. This attribute is manditory
  • context-service - The context service to use, if not supplied, the default context service is used.
  • thread-factory - The name of the thread factory, if not supplied, the default thread factory is used.
  • hung-task-threshold - how long, in milliseconds, to allow threads to run for before they are considered unresponsive. (default=0, 0=no limit, min=0)
  • long-running-tasks - Whether this is a short or long running thread. (default=false)
  • core-threads - The number of threads within the executors thread pool, including idle threads.  This attribute is mandatory. (min=0)
  • keepalive-time - How long threads can remain idle when the number of threads is greater than the core-thread size. This attribute is manditory. (min=0, default=60000)
  • reject-policy - How to handle a failed task. 'ABORT' will cause an exception to be thrown; 'RETRY_ABORT' which will cause a retry, and then an abort if the retry fails. (default=ABORT) 
To view your executor in the Wildfly Admin console, login, and navigate to Runtime > JNDI View > java:jboss > ee > concurrent.  Here, you can see all the concurrent resources including your newly configured scheduledexecutor.


Note: You will notice that I have used the JNDI name of java:jboss/ee/concurrency/scheduler/MyScheduledExectutorService, which at first glance looks excessively long. Using this path ensures that the resource shows under concurrency/scheduler list in the Wildfly admin console.



September 18, 2013

Simple Concurrency Example with Wildfly

Concurrency is the ability to run several threads in parallel, within a single process.

Since its origin Java has had java.lang.Thread for dealing with concurrency. With Java SE 5 improved support was added with the java.util.concurrency package.

Enterprise containers manage their own thread pools and ensure that the other Java EE services are available to these threads. Creating threads using the concurrency API, provided by Java SE, is not recommended in an enterprise environment as there is no guarantee that your thread would have access to these services.

By using the new Concurrency Utils you can run asynchronous operations with java.util.concurrent.ExecutorService which will result in your thread being managed by the container.

The main concurrency components are:

ManagedExecutorService - used to execute tasks in a second thread. These threads are started and managed by the container

ManagedScheduledExecutorService - Same as the ManagedExecutorService except that you can schedule the thread to start as specific times

ContextService - used for creating dynamic proxy objects

ManagedThreadFactory - used by applications to create threads that are managed by the container

Example

This example demonstrates the use of the ManagedExecutorService.

First we need to create a task object that implements Callable. Within the call() method we will define the work that we want carried out in a separate thread.

public class ReportTask implements Callable<Report> {

    Logger logger = Logger.getLogger(getClass().getSimpleName());

    public Report call() {
        try {
            Thread.sleep(3000);
        catch (InterruptedException e) {
            logger.log(Level.SEVERE, "Thread interrupted", e);
        }
    return new Report();
    }
}

Then we need to invoke the task by passing it though to the submit() method of the ManagedExecutorService.

@Stateless
public class ReportBean {

    @Resource
    private ManagedExecutorService executorService;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Future<Report> future = executorService.submit(reportTask);
    }
}

By not specifying the lookup attribute of the @Resource annotation, Wildfly will inject a managed executor service with default configuration as configured within the ee subsystem in standalone.xml.

<subsystem xmlns="urn:jboss:domain:ee:2.0">
    <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
    <jboss-descriptor-property-replacement>true</jboss-descriptor-property-replacement>
    <concurrent>
        <default-context-service/>
        <default-managed-thread-factory/>
        <default-managed-executor-service hung-task-threshold="60000" core-threads="5" max-threads="25" keepalive-time="5000"/>
        <default-managed-scheduled-executor-service hung-task-threshold="60000" core-threads="2" keepalive-time="3000"/>
    </concurrent>
</subsystem>