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); + } + } +}