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:
- Compiling C code;
- 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:
- Generate the SWIG wrapper;
- Compile the library;
- 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:
on Windows, or
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\java>set 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.
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:
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:
// Carries out a match for a mobile User-Agent. Match match = provider.getMatch(mobileUserAgent); System.out.println("Mobile User-Agent: " + mobileUserAgent); System.out.println(" IsMobile: " + match.getValue("IsMobile"));
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.