WURFL Microservice for Java

Note: Before getting started, you will need access to a running instance of the WURFL Microservice HTTP Server, either through ScientiaMobile's Docker Registry, the AWS Marketplace, or any other distribution channel.

The Java API package for WURFL Microservice contains the WM Client JAR file and an example project for Java 6 and above.


WURFL Capabilities and API


WURFL Capabilities: Device properties represented in WURFL. While users of the WURFL Microservice for Docker have access to the list of licensed capabilities, customers who obtained the product through the AWS Marketplace will have access to the WURFL capability list, predefined for the AMI they have acquired. Please note that there are two types of capabilities supported in WURFL:

  • Static Capabilities: Device properties associated to a WURFL device profile. They can be tracked to an actual <capability> element in the wurfl.xml file.

  • Virtual Capabilities: Introduced in API 1.5, virtual capabilities support an algorithmic computational component which greatly augments the power of WURFL at run-time. They can also rely on certain static capabilities under the hood.

WURFL API: Given an HTTP Request and a capability, the WURFL API will return the property value. WURFL has historically supported APIs for all main programming platforms.


Obtaining, Installing and Running the WURFL API


In order to use the WURFL API that operates with WURFL Microservice, please follow these instructions:

  1. Obtain the package with the API library from your HTTP Server (/download endpoint).

  2. Unzip the content of the package into your preferred location.

  3. Install the wmclient-{version_number}.jar file in a Maven repository of your choice.

  4. Go to the example project directory and edit Example.java, modifying the Create() call to include the public IP address of your AMI instance or Docker container service (e.g. replacing localhost with the IP address of your running AMI in AWS Marketplace, or the address of your Docker container service).

Note: There are multiple ways in which a service deployed through Docker can be exposed to the world around it. Please refer to your DevOps if in doubt of the actual address at which the service is running.

  1. In the root directory of the example project (contains the pom.xml file), compile the example using mvn clean install. A JAR file called wmclient-example-{version_number}-jar-with-dependencies.jar will be created inside the directory target.

  2. Run the example JAR file: java -jar wmclient-example-{version_number}-jar-with-dependencies.jar

The sample code in Example.java will look like the following:

package com.scientiamobile.wmclient.example;

import com.scientiamobile.wurfl.wmclient.*;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;

import static java.lang.System.out;

public class Example {

    public static void main(String[] args) {


        try {
            // First we need to create a WM client instance, to connect to our WM server API at the specified host and port.
            WmClient client = WmClient.create("http", "localhost", "8080", "");
            // We ask Wm server API for some Wm server info such as server API version and info about WURFL API and file used by WM server.
            Model.JSONInfoData info = client.getInfo();
            out.println("Printing WM server information");
            out.println("WURFL API version: " + info.getWurflApiVersion());
            out.println("WM server version:  " + info.getWmVersion());
            out.println("Wurfl file info: " + info.getWurflInfo());

            String ua = "Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A5000 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";

            // By setting the cache size we are also activating the caching option in WM client. In order to not use cache, you just to need to omit setCacheSize call
            client.setCacheSize(100000);

            // set the capabilities we want to receive from WM server
            client.setRequestedStaticCapabilities(new String[]{"brand_name", "model_name"});
            client.setRequestedVirtualCapabilities(new String[]{"is_smartphone", "form_factor"});

            out.println();
            out.println("Detecting device for user-agent: " + ua);

            // Perform a device detection calling WM server API
            Model.JSONDeviceData device = client.lookupUseragent(ua);
            // Applicative error, ie: invalid input provided
            if (device.error != null && device.error.length() > 0) {
                out.println("An error occurred: " + device.error);
            } else {
                // Let's get the device capabilities and print some of them
                Map<String, String> capabilities = device.capabilities;
                out.println("Detected device WURFL ID: " + capabilities.get("wurfl_id"));
                out.println("Device brand & model: " + capabilities.get("brand_name") + " " + capabilities.get("model_name"));
                out.println("Detected device form factor: " + capabilities.get("form_factor"));
                if (capabilities.get("is_smartphone").equals("true")) {
                    out.println("This is a smartphone");
                }

                // Iterate over all the device capabilities and print them
                out.println("All received capabilities");
                Iterator<String> it = capabilities.keySet().iterator();
                while (it.hasNext()) {
                    String k = it.next();
                    out.println(k + ": " + capabilities.get(k));
                }
            }

            // Get all the device manufacturers, and print the first twenty
            int limit = 20;
            String[] deviceMakes = client.getAllDeviceMakes();
            out.printf("Print the first %d Brand of %d retrieved from server\n", limit, deviceMakes.length);

            // Sort the device manufacturer names
            Arrays.sort(deviceMakes);
            for (int i = 0; i < limit; i++) {
                out.printf(" - %s\n", deviceMakes[i]);
            }

            // Now call the WM server to get all device model and marketing names produced by Apple
            out.println("Print all Model for the Apple Brand");
            Model.JSONModelMktName[] devNames = client.getAllDevicesForMake("Apple");

            // Sort ModelMktName objects by their model name
            Arrays.sort(devNames, new ByModelNameComparer());

            for (Model.JSONModelMktName modelMktName : devNames) {
                out.printf(" - %s %s\n", modelMktName.modelName, modelMktName.marketingName);
            }

            // Now call the WM server to get all operative system names
            out.println("Print the list of OSes");
            String[] oses = client.getAllOSes();
            // Sort and print all OS names
            Arrays.sort(oses);
            for (String os : oses) {
                out.printf(" - %s\n", os);
            }

            // Let's call the WM server to get all version of the Android OS
            out.println("Print all versions for the Android OS");
            String[] osVersions = client.getAllVersionsForOS("Android");
            // Sort all Android version numbers and print them.
            Arrays.sort(osVersions);
            for (String ver : osVersions) {
                out.printf(" - %s\n", ver);
            }
            // Cleans all client resources. Any call on client API methods after this one will throw a WmException
            client.destroyConnection();
        } catch (WmException e) {
            // problems such as network errors  or internal server problems
            out.println("An error has occurred: " + e.getMessage());
            e.printStackTrace();
        }

    }
}


// Comparator used to sort JSONModelMktName objects according to their model name property, for which is used the String natural ordering.
class ByModelNameComparer implements Comparator<Model.JSONModelMktName> {

    @Override
    public int compare(Model.JSONModelMktName o1, Model.JSONModelMktName o2) {

        if (o1 == null && o2 == null) {
            return 0;
        }

        if (o1 == null && o2 != null) {
            return 1;
        }

        if (o1 != null && o2 == null) {
            return -1;
        }

        return o1.modelName.compareTo(o2.modelName);
    }
}

If you are using device detection from code running as part of an HTTP server, it is highly recommended that you pass the complete HTTPServletRequest object to the lookupRequest method as follows:

Model.JSONDeviceData device = client.lookupRequest(request)

This will provide optimal detection accuracy. For a complete reference of all static and virtual capabilities, you can refer to this document. Please note that WURFL Microservice for the AWS Marketplace comes with a predefined set of capabilities.


Note: you can find a complete reference of the wmclient API here


Error in case of Missing Capabilities

As mentioned above, depending on the configuration of your WURFL Microservice, one or more WURFL capabilities may be unavailable. In this case, the JSONDeviceData.Capabilities map will not contain an entry for those capabilities and the caller will get a return value of zero for it (null).

Presence of a capability can be checked with:

if(JSONDeviceData.capabilities.containsKey("has_cellular_radio") {
    value = JSONDeviceData.capabilities.get("has_cellular_radio");
}

Additional capabilities can always be obtained by upgrading to a greater version of the AMIs in the AWS Marketplace or by contacting ScientiaMobile to license additional capabilities for the Docker Image or other products.




© 2018 ScientiaMobile Inc.
All Rights Reserved.

NOTICE: All information contained herein is, and remains the property of ScientiaMobile Incorporated and its suppliers, if any. The intellectual and technical concepts contained herein are proprietary to ScientiaMobile Incorporated and its suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior written permission is obtained from ScientiaMobile Incorporated.