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



March 10, 2015

Obtaining a reference to a CDI managed bean

Most of the time you can inject your CDI beans using the @Inject annotation. There may be occasions when you need to access your CDI beans inside a class where you can not use @Inject, you have a couple of options.

To programmatically access a CDI managed bean, first you need to get hold of the BeanManager (analogous to the ApplicationContext in Spring), by using CDI.current() or by doing a JNDI lookup.

Using CDI.current()
BeanManager bm = CDI.current().getBeanManager();

Using JNDI:
BeanManager bm = null;
try {
    InitialContext context = new InitialContext();
    bm = (BeanManager) context.lookup("java:comp/BeanManager");
} catch (Exception e) {
    e.printStackTrace();
}

Now you have the BeanManager you can access your CDI beans by doing either a type-based lookup or a name-based lookup.

Type based:
Bean<CrudService> bean = (Bean<CrudService>) bm.getBeans(CrudService.class).iterator().next();
CreationalContext<CrudService> ctx = bm.createCreationalContext(bean);
CrudService crudService = (CrudService) bm.getReference(bean, CrudService.class, ctx);

Name-based
Bean bean = bm.getBeans("crudService").iterator().next();
CreationalContext ctx = bm.createCreationalContext(bean);
CrudService crudService = bm.getReference(bean, bean.getClass(), ctx);

When using name-based lookup, your name has to match the value you pass into your @Named annotation. If do not pass a value then it is the name of your class, in camel case. Example:
@Named("crudService")
public class CrudService {}

And a full code example using CDI.current() and type-based lookup:
BeanManager bm = CDI.current().getBeanManager();
Bean<CrudService> bean = (Bean<CrudService>) bm.getBeans(CrudService.class).iterator().next();
CreationalContext<CrudService> ctx = bm.createCreationalContext(bean);
CrudService crudService = (CrudService) bm.getReference(bean, CrudService.class, ctx);


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 :)

January 5, 2015

JavaMail example with Zoho/GMail using SMTPS

Here is a simple example of how to send emails securely using JavaMail via your Gmail or Zoho account.

The first example uses TLS, which should be your preferred encryption mechanism. The second example uses SSL.

The only difference between the two mechanisms is the port number, and the mail.smtp.startXXX.enable property.

For SSL use:

port 465
mail.smtp.startssl.enable

For TLS use:

port 987
mail.smtp.starttls.enable
 
Get the source on GitHub here

Example 1: Zoho/Gmail with TLS

package com.ritchie.email;

import java.util.Date;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendEmailService {

    private Logger logger = Logger.getLogger(SendEmailService.class.getName());

    public void sendEmail() {

        final String GMAIL_HOST = "smtp.gmail.com";
        final String ZOHO_HOST = "smtp.zoho.com";
        final String TLS_PORT = "897";

        final String SENDER_EMAIL = "username@zoho.com";
        final String SENDER_USERNAME = "username@zoho.com";
        final String SENDER_PASSWORD = "zoho-password";

        // protocol properties
        Properties props = System.getProperties();
        props.setProperty("mail.smtps.host", ZOHO_HOST); // change to GMAIL_HOST for gmail                                                         // for gmail
        props.setProperty("mail.smtp.port", TLS_PORT);
        props.setProperty("mail.smtp.starttls.enable", "true");
        props.setProperty("mail.smtps.auth", "true");
        // close connection upon quit being sent
        props.put("mail.smtps.quitwait", "false");

        Session session = Session.getInstance(props, null);

        try {
            // create the message
            final MimeMessage msg = new MimeMessage(session);

            // set recipients and content
            msg.setFrom(new InternetAddress(SENDER_EMAIL));
            msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipient@gmail.com", false));
            msg.setSubject("Demo");
            msg.setText("Message Sent via JavaMail", "utf-8", "html");
            msg.setSentDate(new Date());

            // this means you do not need socketFactory properties
            Transport transport = session.getTransport("smtps");

            // send the mail
            transport.connect(ZOHO_HOST, SENDER_USERNAME, SENDER_PASSWORD);
            transport.sendMessage(msg, msg.getAllRecipients());
            transport.close();

        } catch (MessagingException e) {
            logger.log(Level.SEVERE, "Failed to send message", e);

        }
    }
}

Example 2: Zoho/Gmail with SSL

package com.ritchie.email;

import java.util.Date;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendEmailService {

    private Logger logger = Logger.getLogger(SendEmailService.class.getName());

    public void sendEmail() {

        final String GMAIL_HOST = "smtp.gmail.com";
        final String ZOHO_HOST = "smtp.zoho.com";
        final String SSL_PORT = "465";

        final String SENDER_EMAIL = "username@zoho.com";
        final String SENDER_USERNAME = "username@zoho.com";
        final String SENDER_PASSWORD = "zoho-password";

        // protocol properties
        Properties props = System.getProperties();
        props.setProperty("mail.smtps.host", ZOHO_HOST); // change to GMAIL_HOST for gmail                                                         // for gmail
        props.setProperty("mail.smtp.port", SSL_PORT);
        props.setProperty("mail.smtp.startssl.enable", "true");
        props.setProperty("mail.smtps.auth", "true");
        // close connection upon quit being sent
        props.put("mail.smtps.quitwait", "false");

        Session session = Session.getInstance(props, null);

        try {
            // create the message
            final MimeMessage msg = new MimeMessage(session);

            // set recipients and content
            msg.setFrom(new InternetAddress(SENDER_EMAIL));
            msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipient@gmail.com", false));
            msg.setSubject("Demo");
            msg.setText("Message Sent via JavaMail", "utf-8", "html");
            msg.setSentDate(new Date());

            // this means you do not need socketFactory properties
            Transport transport = session.getTransport("smtps");

            // send the mail
            transport.connect(ZOHO_HOST, SENDER_USERNAME, SENDER_PASSWORD);
            transport.sendMessage(msg, msg.getAllRecipients());
            transport.close();

        } catch (MessagingException e) {
            logger.log(Level.SEVERE, "Failed to send message", e);

        }
    }
} 


January 3, 2015

Installing Meld on Mac OS using macports

After playing around with various merge tools on Mac, I have come to the conclusion that none match the ease of use that Meld offers. Here is how I managed to install it on my Mac OS X 10.8.5.
  1. First install macports
  2. If you are running Mac OS 10.8 and greater, you will need to install xquartz which provides the X Window system required for Meld. If you have Mac OS prior to 10.8 you can skip this step.
  3. Install Meld and its dependencies:
    sudo port install rarian
    sudo port install meld
    
  4. Set your locale (I hard coded this so I do not have to export it each time) by updating the /opt/local/bin/meld script by changing line 75 from:
    locale.setlocale(locale.LC_ALL,'')
    to
    locale.setlocale(locale.LC_ALL,'en_US')
  5. Start the service at boot
    launchctl load -w /Library/LaunchAgents/org.freedesktop.dbus-session.plist
  6. Finally run meld using spotlight or via the command line: /opt/local/bin/meld

 

Notes: 

If you try to run Meld without having xquartz installed then you will get the following error:
(process:65163): Gtk-WARNING **: Locale not supported by C library.
 Using the fallback 'C' locale.
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/gtk-2.0/gtk/__init__.py:57: GtkWarning: could not open display
  warnings.warn(str(e), _gtk.Warning)
/opt/local/bin/meld:126: GtkWarning: GtkIconTheme *gtk_icon_theme_get_for_screen(GdkScreen *): assertion 'GDK_IS_SCREEN (screen)' failed
  gtk.icon_theme_get_default().append_search_path(meld.paths.icon_dir())
Traceback (most recent call last):
  File "/opt/local/bin/meld", line 126, in 
    gtk.icon_theme_get_default().append_search_path(meld.paths.icon_dir())
AttributeError: 'NoneType' object has no attribute 'append_search_path'
logout 
 

Reference:

http://support.apple.com/en-us/HT201341
http://thebugfreeblog.blogspot.com/2014/03/installing-meld-on-mac-os-x.html

September 29, 2014

LocalDate java 8 Custom Serializer Jackson JSON Example

In this previous example we use serialize and deserialize classes provided by a Jackson third party datatype. For more control over the date formatting you can opt to create your own serialize and deserialize classes.

WildFly 8.1.0 uses Jackson 2.3.2 so we can add the following dependencies to the pom with a scope of provided:
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.4.2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.4.2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.2</version>
    <scope>provided</scope>
</dependency>
Then on the LocalDate property of your bean add the following annotations:
public class MyBean {

    @JsonDeserialize(using = JsonDateDeserializer.class)
    @JsonSerialize(using = JsonDateSerializer.class)
    private LocalDate date;
 
    public LocalDate getDate() {
        return date;
    }

    private void setDate(LocalDate date) {
        this.date = date;
    }
} 
Now create the custom JsonDateSerializer:
public class JsonDateSerializer extends JsonSerializer<LocalDate> {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
 
    @Override
    public void serialize(LocalDate date, JsonGenerator generator,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {

        String dateString = date.format(formatter);
        generator.writeString(dateString);
    }
}
And now the custom JsonDateDeserializer:
public class JsonDateDeserializer extends JsonDeserializer<LocalDate> {

    @Override
    public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {

        ObjectCodec oc = jp.getCodec();
        TextNode node = (TextNode) oc.readTree(jp);
        String dateString = node.textValue();

        Instant instant = Instant.parse(dateString);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        LocalDate date = LocalDate.of(dateTime.getYear(), dateTime.getMonth(), dateTime.getDayOfMonth());
        return date;
    }
}

NOTE: The package names have changed in Jackson 2. When you use the Jackson annotations make sure you import the one from the com.fasterxml.jackson.databind.annotation.* package and not the ones from the org.codehaus.jackson.map.annotate.* package. If you import the latter, your annotations will be ignored. WildFly 8 does not load the classes from the 1.9.2 jackson module.

September 23, 2014

Java 8 LocalDate with Jackson Serialize and Deserialize Example - RESTful WS

Although I having using Joda Time for years, it is now time to migrate over to the Java 8 Date and Time API (JSR310), and make use of the new LocalDate and LocalTime classes.

WildFly 8.1.0 uses Jackson 2.3.2 which does not know how to (de)serialize the JSR310 Date Time classes. So in order to use the Date and Time API we need to add a Jackson third party datatype dependency to our pom:
<dependency>
    <groupid>com.fasterxml.jackson.datatype</groupid>
    <artifactid>jackson-datatype-jsr310</artifactid>
    <version>2.4.0</version>
</dependency>
Then to deserialize your LocalDate add the @JsonDeserialize annotation and use the LocalDateDeserializer:
@Path("/resource")
@Produces("application/json")
public class MyRestResource {

    @GET
    @Path("now")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    public LocalDate get() {
        return LocalDate.now();
    }
}
To serialize your LocalDate add @JsonSerialize annotation and use the LocalDateSerializer:
@JsonSerialize(using = LocalDateSerializer.class)

To create your own serializer/deserializer check this example, which shows you how you can format the date.

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.