JavaProjectStructure

How to Use the New Hash Trie algorithm in Java

Ben Shillito

8/21/2017 1:33 PM

Device Detection Java C API Development

51Degrees explains how to call the C Hash Trie API within Java.

Introduction

The new Hash Trie algorithm is by far the fastest method of detecting devices from their User-Agents (see the blog post for details). To retain this speed in Java, it is necessary to interface with the compiled C/C++ to keep all the heavy lifting in the C world and away from Java objects and types. This can be done very simply with a SWIG generated wrapper.

This blog will go through the steps required to create an illustrative example of how to call the C Hash Trie API within Java. The following assumes a sufficent knowledge of:

  1. Compiling C code;
  2. Java programming;

Before starting, you will need to get hold of the new Hash Trie source which is available on GitHub. You will also need to download the Hash Trie Device-Data file, access to the file can be obtained by signing up for a free subscription.

The steps involved are:

  1. Generate the SWIG wrapper;
  2. Compile the library;
  3. Build the JAR.

And that's all there is.

Generate the SWIG Wrapper

If it is not already, then you will need to install SWIG on your system. This can be done through apt in Linux, and the Windows version can be found on the SWIG downloads page.

First clone the Device-Detection repository, open a terminal and move to the src/trie directory. Generating the wrapper files is then done with the command:

swig -java -c++ -package FiftyOneDegreesTrieV3 -o 51Degrees_java.cpp 51Degrees.i

This will generate the 51Degrees_java.cpp which will be compiled in the library, the Java classes as defined in 51Degrees.i, and a JNI class for interfacing with the C++ layer.

Compile the Library

Attached at the bottom of this article is a template project to get started, it contains the scripts to build the library in both Windows and Linux, and a template Java project. Extract the folder to the Device-Detection directory. Now in a terminal (Visual Studio command prompt in Windows, or any Bash shell in Linux), go to the newly extracted Device-Detection/java directory.

Then build the shared library to the resources directory with the command:

build.bat

on Windows, or

./build.sh

on Linux.

The output should look like this:

D:\Workspace\Device-Detection\java>build.bat D:\Workspace\Device-Detection\java>set JAVA_INCLUDE=C:\Program Files\Java\jdk1.8.0_121\include D:\Workspace\Device-Detection\javaset JAVA_WIN32=C:\Program Files\Java\jdk1.8.0_121\include\win32 D:\Workspace\Device-Detection\java>copy ..\src\trie\*.java trie\src\main\java\FiftyOneDegreesTrieV3\ ..\src\trie\FiftyOneDegreesTrieV3.java ..\src\trie\FiftyOneDegreesTrieV3JNI.java ..\src\trie\MapStringString.java ..\src\trie\Match.java ..\src\trie\Provider.java ..\src\trie\SWIGTYPE_p_std__string.java ..\src\trie\VectorString.java 7 file(s) copied. cl /Fo:obj/ /Fe:trie/src/main/resources/FiftyOneDegreesTrieV3 /O2 /LD /EHsc ..\src\trie\51Degrees.c ..\src\threading.c ..\src\trie\Provider.cpp ..\src\trie\Match.cpp ..\src\trie\51Degrees_java.cpp /I "C:\Program Files\Java\jdk1.8.0_121\include" /I "C:\Program Files\Java\jdk1.8.0_121\include\win32" Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved. 51Degrees.c threading.c Generating Code... Compiling... Provider.cpp Match.cpp 51Degrees_java.cpp Generating Code... Microsoft (R) Incremental Linker Version 14.00.24215.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:trie/src/main/resources/FiftyOneDegreesTrieV3.dll /dll /implib:trie/src/main/resources/FiftyOneDegreesTrieV3.lib obj/51Degrees.obj obj/threading.obj obj/Provider.obj obj/Match.obj obj/51Degrees_java.obj Creating library trie/src/main/resources/FiftyOneDegreesTrieV3.lib and object trie/src/main/resources/FiftyOneDegreesTrieV3.exp

in Windows, or in Linux, an empty output with no errors.

If it does not, then make sure the JAVA_HOME environment variable is defined, and the terminal has a compiler accessible.

The DLL (or SO if building in Linux) is now located in the java/trie/src/main/resources directory ready to be called by the previously generated Java classes.

Build the JAR

Open up the java/trie directory as a project in a Java IDE, and you will see a project structure like Figure 1.

JavaProjectStructure
Figure 1: Project Structure as Displayed in IntelliJ

The final step is to hit build. A JAR will then be produced in the target directory.

Getting Started Example

In the project you may have noticed there is a file named GettingStarted.java. This is standard example to show how the API can be used.

Firstly, the FiftyOneDegreesTrieV3 classes are included in the file:

import FiftyOneDegreesTrieV3.* ;

Then the DLL is loaded, and the Provider created:

// Load the C/C++ native library. Uncomment dll line for windows and so line in linux. URL res = FiftyOneDegreesTrieV3.class.getResource("/FiftyOneDegreesTrieV3.dll"); // URL res = FiftyOneDegreesTrie.class.getResource("/FiftyOneDegreesTrieV3.so"); System.load(res.getPath()); // Create a new provider. Provider provider = new Provider(<"../../data/51Degrees-EnterpriseV3.4.trie");

Now that the Provider has been created, a match can be carried out:

Note: Wrapping the match object creation in a try ensures the GC removes the object efficiently.

// Carries out a match for a mobile User-Agent. try { Match match = provider.getMatch(mobileUserAgent); System.out.println(Mobile User-Agent: " + mobileUserAgent); System.out.println(" IsMobile: " + match.getValue("IsMobile")); } finally { provider.delete(); }

The above code in a project will first get a match for the User-Agent string defined by mobileUserAgent. It will then print the value of the IsMobile property.

Including in a Project

The JAR can now be set as a dependancy in an external project by. Then, by using code similar to that in the above example, any Java project can benefit from the new, faster, Hash Trie device detection API.