From cf5e69ff3b040db687491ca53f8429f112c12921 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 16 Sep 2026 22:23:55 +0100 Subject: [PATCH] FEAT: Let the on-premise web example take its port and data file from the environment The shared Selenium contract tests drive each web example as an already running server. The on-premise example was fixed to port 8081, waited on Enter, and only read the data file from TestDataFile. It now honours PORT the same way the cloud example does, joining the server instead of waiting on stdin, and reads the data file from 51DEGREES_DD_PATH first, then TestDataFile, then the Lite file. A unit test pins that order. --- README.md | 17 ++- .../examples/web/GettingStartedWebOnPrem.java | 19 +++- .../main/webapp/WEB-INF/51Degrees-OnPrem.xml | 7 +- .../web/OnPremDataFileOptionTest.java | 101 ++++++++++++++++++ 4 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java diff --git a/README.md b/README.md index 61a4c91..7aa2ce9 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The tables below describe the examples available in this repository. | Example | Description | |--------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | GettingStarted (Console) | How to use the 51Degrees on-premise device detection API to determine details about a device based on its User-Agent and User-Agent Client Hints HTTP header values. | -| GettingStarted (Web) | How to use the 51Degrees Cloud service to determine details about a device as part of a simple Java servlet website. | +| GettingStarted (Web) | How to use the 51Degrees on-premise device detection API to determine details about a device as part of a simple Java servlet website. | | Metadata | How to access the meta-data that relates to things like the properties populated device detection. | | MatchMetrics | How to view metrics associated with the properties of processing with a Device Detection engine. | | OfflineProcessing | Example showing how to ingest a file containing data from web requests and perform detection against the entries. | @@ -101,6 +101,21 @@ Use them with relevant example class entrypoints like: java -cp ./console/target/device-detection-java-examples.console-4.4.20-jar-with-dependencies.jar fiftyone.devicedetection.examples.console.OfflineProcessing ``` +### Web examples + +The web examples are run from the root of this repository, because they find their +web content by a path relative to it. They listen on port 8081 and stop when Enter +is pressed. Set the `PORT` environment variable to listen on another port, in which +case the example runs until the process is stopped: + +```bash +PORT=8100 java -jar ./web/getting-started.onprem/target/device-detection-java-examples.web.getting-started.onprem-4.4.20-jar-with-dependencies.jar +``` + +The on-premise web example takes its data file from the `51DEGREES_DD_PATH` +environment variable, then from `TestDataFile`, and otherwise uses the free Lite file +in `device-detection-data`. + ### Native library access The on-premise examples use a native library, and diff --git a/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java b/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java index af17170..ff57026 100644 --- a/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java +++ b/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java @@ -45,6 +45,14 @@ * supplied filter which automatically creates and configures a device detection pipeline. *

* The configuration file for the pipeline is at src/main/webapp/WEB-INF/51Degrees-OnPrem.xml + *

+ * The data file is taken from the 51DEGREES_DD_PATH environment variable, then + * from TestDataFile (an environment variable or system property), and otherwise + * the free Lite file in device-detection-data is used. + *

+ * The server listens on port 8081 and stops when Enter is pressed. If the PORT + * environment variable is set, the server listens on that port instead and runs + * until the process is stopped, which is how automated tests start it. */ public class GettingStartedWebOnPrem extends HttpServlet { private static final long serialVersionUID = 1734154705981153540L; @@ -55,8 +63,15 @@ public static void main(String[] args) throws Exception { configureLogback(getFilePath("logback.xml")); logger.info("Running Example {}", GettingStartedWebOnPrem.class); - // start Jetty with this WebApp - EmbedJetty.runWebApp(resourceBase, 8081); + String portEnv = System.getenv("PORT"); + if (portEnv != null) { + // Automated runs (e.g. the unified Selenium suite) inject a port and have no + // interactive stdin, so keep the server alive by joining it instead of waiting on Enter. + EmbedJetty.startWebApp(resourceBase, Integer.parseInt(portEnv)).join(); + } else { + // start Jetty with this WebApp + EmbedJetty.runWebApp(resourceBase, 8081); + } } FlowDataProviderCore flowDataProvider = new FlowDataProviderCore.Default(); diff --git a/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml b/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml index 49e13dc..547ea06 100644 --- a/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml +++ b/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml @@ -27,7 +27,12 @@ false false - ${TestDataFile:-device-detection-data/51Degrees-LiteV4.1.hash} + + ${51DEGREES_DD_PATH:-${TestDataFile:-device-detection-data/51Degrees-LiteV4.1.hash}} LowMemory DeviceDetectionHashEngine diff --git a/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java b/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java new file mode 100644 index 0000000..b7c15bf --- /dev/null +++ b/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java @@ -0,0 +1,101 @@ +/* ********************************************************************* + * This Original Work is copyright of 51 Degrees Mobile Experts Limited. + * Copyright 2026 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.web; + +import fiftyone.pipeline.core.configuration.PipelineOptions; +import fiftyone.pipeline.core.configuration.PipelineOptionsFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static fiftyone.devicedetection.examples.web.GettingStartedWebOnPrem.resourceBase; +import static fiftyone.pipeline.util.FileFinder.getFilePath; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeTrue; + +/** + * Checks the order in which the on-premise web example picks its data file, + * being 51DEGREES_DD_PATH first, then TestDataFile, then the Lite file. + * System properties stand in for the environment variables, because the + * lookup reads either and a test cannot set an environment variable. + */ +public class OnPremDataFileOptionTest { + private static final String DD_PATH = "51DEGREES_DD_PATH"; + private static final String TEST_DATA_FILE = "TestDataFile"; + private static final String LITE = + "device-detection-data/51Degrees-LiteV4.1.hash"; + + private String savedDdPath; + private String savedTestDataFile; + + @Before + public void saveProperties() { + // An environment variable of either name would take precedence over + // the system properties set here, so the test cannot run. + assumeTrue(System.getenv(DD_PATH) == null); + assumeTrue(System.getenv(TEST_DATA_FILE) == null); + assumeTrue(System.getenv(TEST_DATA_FILE.toUpperCase()) == null); + savedDdPath = System.getProperty(DD_PATH); + savedTestDataFile = System.getProperty(TEST_DATA_FILE); + System.clearProperty(DD_PATH); + System.clearProperty(TEST_DATA_FILE); + } + + @After + public void restoreProperties() { + restore(DD_PATH, savedDdPath); + restore(TEST_DATA_FILE, savedTestDataFile); + } + + @Test + public void usesLiteWhenNothingIsSet() throws Exception { + assertEquals(LITE, dataFile()); + } + + @Test + public void usesTestDataFileWhenOnlyThatIsSet() throws Exception { + System.setProperty(TEST_DATA_FILE, "from-test-data-file.hash"); + assertEquals("from-test-data-file.hash", dataFile()); + } + + @Test + public void prefersDdPathOverTestDataFile() throws Exception { + System.setProperty(TEST_DATA_FILE, "from-test-data-file.hash"); + System.setProperty(DD_PATH, "from-dd-path.hash"); + assertEquals("from-dd-path.hash", dataFile()); + } + + private static String dataFile() throws Exception { + PipelineOptions options = PipelineOptionsFactory.getOptionsFromFile( + getFilePath(resourceBase) + "/WEB-INF/51Degrees-OnPrem.xml"); + return options.findAndSubstitute("DeviceDetectionHashEngine", "DataFile"); + } + + private static void restore(String name, String value) { + if (value == null) { + System.clearProperty(name); + } else { + System.setProperty(name, value); + } + } +}