51Degrees Device Detection Java  4.4

Device detection services for 51Degrees Pipeline


This example is available in full on GitHub.

/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2023 51 Degrees Mobile Experts Limited, Davidson House,
* Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
* This Original Work is licensed under the European Union Public Licence
* (EUPL) v.1.2 and is subject to its terms as set out below.
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */
package fiftyone.devicedetection.examples.console;
import fiftyone.devicedetection.DeviceDetectionPipelineBuilder;
import fiftyone.devicedetection.examples.shared.DataFileHelper;
import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine;
import fiftyone.devicedetection.shared.DeviceData;
import fiftyone.pipeline.core.data.FlowData;
import fiftyone.pipeline.core.flowelements.Pipeline;
import fiftyone.pipeline.engines.Constants;
import fiftyone.pipeline.engines.data.AspectPropertyValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
import static fiftyone.common.testhelpers.LogbackHelper.configureLogback;
import static fiftyone.devicedetection.examples.shared.PropertyHelper.asString;
import static fiftyone.pipeline.util.FileFinder.getFilePath;
public class OfflineProcessing {
static final Logger logger = LoggerFactory.getLogger(OfflineProcessing.class);
// This 51degrees "Lite" file (distributed with the source) needs to
// be somewhere in the project space
// Note that the Lite data file is only used for illustration, and has
// limited accuracy and capabilities. Find out about the Enterprise data
// file here: https://51degrees.com/pricing
public static final String LITE_V_4_1_HASH =
// This 51degrees file of 20,000 examples (distributed with the source)
// needs to be somewhere in the project space
public static final String HEADER_EVIDENCE_YML =
"device-detection-data/20000 Evidence Records.yml";
public static void main(String[] args) throws Exception {
File evidenceFile = getFilePath(HEADER_EVIDENCE_YML);
run(LITE_V_4_1_HASH, Files.newInputStream(evidenceFile.toPath()), System.out);
public static void run(String dataFile, InputStream is, OutputStream os) throws Exception {
String detectionFile;
try {
detectionFile = getFilePath(dataFile).getAbsolutePath();
} catch (Exception e) {
throw e;
---- configure YAML for getting evidence and saving the results ----
DumperOptions dumperOptions = new DumperOptions();
// get a YAML loader to iterate over the device evidence
Yaml yaml = new Yaml(dumperOptions);
Iterator<Object> evidenceIterator = yaml.loadAll(is).iterator();
---- Build a pipeline ----
logger.info("Constructing pipeline with on-premise hash " +
"engine from file " + dataFile);
// Build a new on-premise Hash engine in a try/resources so
// that the pipeline is disposed when done
try (Pipeline pipeline = new DeviceDetectionPipelineBuilder()
.useOnPremise(detectionFile, false)
// inhibit sharing usage for this test, usually
// this should be set "true"
// inhibit auto-update of the data file for this test
// -- Setting the Profile
// For information on profiles see
// https://51degrees.com/documentation/_device_detection__features__performance_options.html
// Low memory profile has detection data streamed from disk on
// demand and is conservative in its use of memory, but
// slower because of disk access
// -- Setting the Graph
// see https://51degrees.com/documentation/_device_detection__hash.html#DeviceDetection_Hash_DataSetProduction
// -- Setting Predictive Power
// see https://51degrees.com/documentation/_device_detection__hash.html#DeviceDetection_Hash_PredictivePower
.build()) {
// get the details of the detection engine from the pipeline,
// to find out what data file we are using
DeviceDetectionHashEngine engine = pipeline.getElement(DeviceDetectionHashEngine.class);
logger.info("Device data file was created {}", engine.getDataFilePublishedDate());
---- Iterate over the evidence ----
// open a writer to collect the results
try (Writer writer = new OutputStreamWriter(os)) {
// read a batch of device data from the stream
int count = 0;
while (evidenceIterator.hasNext() && count < 20) {
// Flow data is the container for inputs and outputs that
// flow through the pipeline a flowdata instance is
// created by the pipeline factory method it's important
// to dispose flowdata - so wrap in a try/resources
try (FlowData flowData = pipeline.createFlowData()) {
// the evidence values in the test YAML data are read
// as a Map<String, String> - add the evidence to the
// flowData
filterEvidence((Map<String, String>) evidenceIterator.next(),
---- Do the detection ----
// carry out device-detection (and other
// pipeline actions) on the evidence
// extract device data from the flowData
DeviceData device = flowData.get(DeviceData.class);
---- use the device data - output to YAML in this case
Map<String, ? super Object> resultMap = new HashMap<>();
resultMap.put("device.ismobile", asString(device.getIsMobile()));
resultMap.put("device.platformname", asString(device.getPlatformName()));
resultMap.put("device.platformversion", asString(device.getPlatformVersion()));
// to look at all device detection properties use the following:
// resultMap.putAll(getPopulatedProperties(device, "device."));
// write document to output stream as a YAML document
yaml.dump(flowData.getEvidence().asKeyMap(), writer);
yaml.dump(resultMap, writer);
// finish the last YAML document
logger.info("Finished processing {} records", count);
if (engine.getDataSourceTier().equals("Lite")) {
logger.warn("You have used a Lite data file which has " +
"limited properties and is of limited accuracy");
logger.info("The example requires an Enterprise data file " +
"to work fully. Find out about the Enterprise " +
"data file here: https://51degrees.com/pricing");
private static Map<String, String> filterEvidence(Map<String, String> evidence, String prefix) {
return evidence.entrySet()
.filter(e -> e.getKey().startsWith(prefix))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
@SuppressWarnings({"SameParameterValue", "unused"})
private static Map<String, Object> getPopulatedProperties(DeviceData data, String prefix) {
return data.asKeyMap().entrySet()
.filter(e -> ((AspectPropertyValue<?>) e.getValue()).hasValue())
.collect(Collectors.toMap(e -> prefix + e.getKey(),
e -> ((AspectPropertyValue<?>)e.getValue()).getValue()));