diff --git a/extra/bundle/pom.xml b/extra/bundle/pom.xml
index 4aa2d3ab359..822ad30ea5d 100644
--- a/extra/bundle/pom.xml
+++ b/extra/bundle/pom.xml
@@ -55,13 +55,11 @@
pb-request-correction
${project.version}
-
diff --git a/extra/modules/WURFL-devicedetection/README.md b/extra/modules/WURFL-devicedetection/README.md
index eeb319eecf8..54a36a5cff2 100644
--- a/extra/modules/WURFL-devicedetection/README.md
+++ b/extra/modules/WURFL-devicedetection/README.md
@@ -19,9 +19,11 @@ The WURFL module populates missing or empty fields in ortb2.device with the foll
- **h**: Screen height in pixels.
- **w**: Screen width in pixels.
- **ppi**: Screen pixels per inch (PPI).
- - **pixelratio**: Screen pixel density ratio.
+ - **pxratio**: Screen pixel density ratio.
- **devicetype**: Device type (e.g., mobile, tablet, desktop).
+ - **js**: Support for JavaScript, where 0 = no, 1 = yes
- **Note**: If these fields are already populated in the bid request, the module will not overwrite them.
+
#### Publisher-Specific Enrichment:
Device enrichment is selectively enabled for publishers based on their account ID.
@@ -30,17 +32,14 @@ The module identifies publishers through the following fields:
`site.publisher.id` (for web environments).
`app.publisher.id` (for mobile app environments).
`dooh.publisher.id` (for digital out-of-home environments).
-```
-### Build prerequisites
+### Building WURFL Module with a licensed WURFL Onsite Java API
-To build the WURFL module, you need to download the WURFL Onsite Java API (both JAR and POM files)
-from the ScientiaMobile private repository and install it in your local Maven repository.
-Access to the WURFL Onsite Java API repository requires a valid ScientiaMobile WURFL license.
-For more details, visit: [ScientiaMobile WURFL Onsite API for Java](https://www.scientiamobile.com/secondary-products/wurfl-onsite-api-for-java/).
+In order to compile the WURFL module in the PBS Java server bundle, you must follow these steps:
-Run the following command to install the WURFL API:
+1 - Download the WURFL Onsite Java API (both JAR and POM files)
+from the ScientiaMobile private repository and install it in your local Maven repository
```bash
mvn install:install-file \
@@ -52,22 +51,26 @@ mvn install:install-file \
-DpomFile=
```
-### Activating the WURFL Module
+2 - add the WURFL Onsite Java API dependency in the WURFL-devicedetection module's `pom.xml`:
-The WURFL module is disabled by default. Building the Prebid Server Java with the default bundle option
-does not include the WURFL module in the server's JAR file.
-
-To include the WURFL module in the Prebid Server Java bundle, follow these steps:
+```xml
+
+ com.scientiamobile.wurfl
+ wurfl
+ ${wurfl.version}
+
+```
+If the WURFL API dependency is not added, the module will compile a demo version that returns sample data, allowing basic testing without an WURFL Onsite Java API license.
-1. Uncomment the WURFL Java API dependency in `extra/modules/WURFL-devicedetection/pom.xml`.
-2. Uncomment the WURFL module dependency in `extra/bundle/pom.xml`.
-3. Uncomment the WURFL module name in the module list in `extra/modules/pom.xml`.
+3 - Remove the `com` directory under `src/main/java` to avoid classloader issues.
-After making these changes, you can build the Prebid Server Java bundle with the WURFL module using the following command:
+4 - Build the Prebid Server Java bundle with the WURFL module using the following command:
```bash
mvn clean package --file extra/pom.xml
```
+**NOTE** - For further automation of WURFL API dependency usage, please check the paragraph
+"Configuring your Builds to work with ScientiaMobile's Private Maven Repository" [on this page](https://docs.scientiamobile.com/documentation/onsite/onsite-java-api).
### Configuring the WURFL Module
diff --git a/extra/modules/WURFL-devicedetection/pom.xml b/extra/modules/WURFL-devicedetection/pom.xml
index da087b44cca..b1f353eed99 100644
--- a/extra/modules/WURFL-devicedetection/pom.xml
+++ b/extra/modules/WURFL-devicedetection/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.19.0-SNAPSHOT
+ 3.22.0-SNAPSHOT
wurfl-devicedetection
@@ -14,16 +14,8 @@
WURFL device detection and data enrichment module
- 1.13.2.1
+ 1.13.3.0
-
-
-
+
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/Device.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/Device.java
new file mode 100644
index 00000000000..ee61c0a29ef
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/Device.java
@@ -0,0 +1,29 @@
+package com.scientiamobile.wurfl.core;
+
+import com.scientiamobile.wurfl.core.exc.VirtualCapabilityNotDefinedException;
+import com.scientiamobile.wurfl.core.exc.CapabilityNotDefinedException;
+import com.scientiamobile.wurfl.core.matchers.MatchType;
+
+public interface Device {
+
+ String getId();
+
+ MatchType getMatchType();
+
+ String getCapability(String name) throws CapabilityNotDefinedException;
+
+ String getVirtualCapability(String name)
+ throws VirtualCapabilityNotDefinedException, CapabilityNotDefinedException;
+
+ int getVirtualCapabilityAsInt(String s) throws VirtualCapabilityNotDefinedException,
+ CapabilityNotDefinedException, NumberFormatException;
+
+ boolean getVirtualCapabilityAsBool(String vcapName) throws VirtualCapabilityNotDefinedException,
+ CapabilityNotDefinedException, NumberFormatException;
+
+ String getWURFLUserAgent();
+
+ int getCapabilityAsInt(String capName) throws CapabilityNotDefinedException, NumberFormatException;
+
+ boolean getCapabilityAsBool(String capName) throws CapabilityNotDefinedException, NumberFormatException;
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/GeneralWURFLEngine.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/GeneralWURFLEngine.java
new file mode 100644
index 00000000000..a349bb082f3
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/GeneralWURFLEngine.java
@@ -0,0 +1,150 @@
+package com.scientiamobile.wurfl.core;
+
+import com.scientiamobile.wurfl.core.cache.CacheProvider;
+import com.scientiamobile.wurfl.core.exc.CapabilityNotDefinedException;
+import com.scientiamobile.wurfl.core.exc.VirtualCapabilityNotDefinedException;
+import com.scientiamobile.wurfl.core.matchers.MatchType;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class GeneralWURFLEngine implements WURFLEngine {
+
+ public GeneralWURFLEngine(String wurflPath) { }
+
+ public static void wurflDownload(String wurflUrl, String dest) {
+ }
+
+ static final Map CAPABILITIES = Map.ofEntries(
+ Map.entry("brand_name", "Google"),
+ Map.entry("model_name", "Pixel 9 Pro XL"),
+ Map.entry("device_os", "Android"),
+ Map.entry("device_os_version", "15.0"),
+ Map.entry("pointing_method", "touchscreen"),
+ Map.entry("is_wireless_device", "true"),
+ Map.entry("is_smarttv", "false"),
+ Map.entry("density_class", "2.55"),
+ Map.entry("resolution_width", "1344"),
+ Map.entry("resolution_height", "2992"),
+ Map.entry("ux_full_desktop", "false"),
+ Map.entry("marketing_name", ""),
+ Map.entry("mobile_browser", "Chrome Mobile"),
+ Map.entry("mobile_browser_version", ""),
+ Map.entry("preferred_markup", "html_web_4_0"),
+ Map.entry("is_connected_tv", "false"),
+ Map.entry("physical_screen_height", "158"),
+ Map.entry("ajax_support_javascript", "true"),
+ Map.entry("can_assign_phone_number", "true"),
+ Map.entry("is_ott", "false"),
+ Map.entry("is_tablet", "false"),
+ Map.entry("physical_form_factor", "phone_phablet"),
+ Map.entry("xhtml_support_level", "4")
+ );
+ static final Map VIRTUAL_CAPABILITIES = Map.of(
+ "advertised_device_os", "Android",
+ "advertised_device_os_version", "15",
+ "pixel_density", "481",
+ "is_phone", "true",
+ "is_mobile", "true",
+ "is_full_desktop", "false",
+ "form_factor", "Smartphone",
+ "is_android", "true",
+ "is_ios", "false",
+ "complete_device_name", "Google Pixel 9 Pro XL"
+ );
+
+ static final Set CAPABILITIES_KEYS = new HashSet<>(CAPABILITIES.keySet());
+ static final Set VIRTUAL_CAPABILITIES_KEYS = new HashSet<>(VIRTUAL_CAPABILITIES.keySet());
+
+ @Override
+ public Set getAllCapabilities() {
+ return CAPABILITIES_KEYS;
+ }
+
+ @Override
+ public Set getAllVirtualCapabilities() {
+ return VIRTUAL_CAPABILITIES_KEYS;
+ }
+
+ @Override
+ public void load() {
+ }
+
+ @Override
+ public void setCacheProvider(CacheProvider cacheProvider) {
+ }
+
+ @Override
+ public Device getDeviceById(String deviceId) {
+ return mockDevice();
+ }
+
+ @Override
+ public Device getDeviceForRequest(Map headers) {
+ return mockDevice();
+ }
+
+ private Device mockDevice() {
+ return new Device() {
+ @Override
+ public String getId() {
+ return "google_pixel_9_pro_xl_ver1_suban150";
+ }
+
+ @Override
+ public MatchType getMatchType() {
+ return MatchType.conclusive;
+ }
+
+ @Override
+ public String getCapability(String name) throws CapabilityNotDefinedException {
+ if (CAPABILITIES.containsKey(name)) {
+ return CAPABILITIES.get(name);
+ } else {
+ throw new CapabilityNotDefinedException(
+ "Capability: " + name + " is not defined in WURFL");
+ }
+ }
+
+ @Override
+ public String getVirtualCapability(String name) throws VirtualCapabilityNotDefinedException,
+ CapabilityNotDefinedException {
+ if (VIRTUAL_CAPABILITIES.containsKey(name)) {
+ return VIRTUAL_CAPABILITIES.get(name);
+ } else {
+ throw new VirtualCapabilityNotDefinedException(
+ "Virtual Capability: " + name + " is not defined in WURFL");
+ }
+ }
+
+ @Override
+ public int getVirtualCapabilityAsInt(String s) throws VirtualCapabilityNotDefinedException,
+ CapabilityNotDefinedException, NumberFormatException {
+ return 0;
+ }
+
+ @Override
+ public boolean getVirtualCapabilityAsBool(String vcapName) throws VirtualCapabilityNotDefinedException,
+ CapabilityNotDefinedException, NumberFormatException {
+ return Boolean.parseBoolean(getVirtualCapability(vcapName));
+ }
+
+ @Override
+ public String getWURFLUserAgent() {
+ return "";
+ }
+
+ @Override
+ public int getCapabilityAsInt(String capName) throws CapabilityNotDefinedException, NumberFormatException {
+ return 0;
+ }
+
+ @Override
+ public boolean getCapabilityAsBool(String capName) throws CapabilityNotDefinedException,
+ NumberFormatException {
+ return Boolean.parseBoolean(getCapability(capName));
+ }
+ };
+ }
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/WURFLEngine.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/WURFLEngine.java
new file mode 100644
index 00000000000..6905947faa0
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/WURFLEngine.java
@@ -0,0 +1,21 @@
+package com.scientiamobile.wurfl.core;
+
+import com.scientiamobile.wurfl.core.cache.CacheProvider;
+
+import java.util.Map;
+import java.util.Set;
+
+public interface WURFLEngine {
+
+ Set getAllCapabilities();
+
+ Set getAllVirtualCapabilities();
+
+ void load();
+
+ void setCacheProvider(CacheProvider cacheProvider);
+
+ Device getDeviceById(String deviceId);
+
+ Device getDeviceForRequest(Map headers);
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/CacheProvider.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/CacheProvider.java
new file mode 100644
index 00000000000..7e190e37491
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/CacheProvider.java
@@ -0,0 +1,4 @@
+package com.scientiamobile.wurfl.core.cache;
+
+public interface CacheProvider {
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/LRUMapCacheProvider.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/LRUMapCacheProvider.java
new file mode 100644
index 00000000000..00de199dece
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/LRUMapCacheProvider.java
@@ -0,0 +1,8 @@
+package com.scientiamobile.wurfl.core.cache;
+
+public class LRUMapCacheProvider implements CacheProvider {
+
+ public LRUMapCacheProvider(int maxSize) {
+
+ }
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/NullCacheProvider.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/NullCacheProvider.java
new file mode 100644
index 00000000000..768617aab7f
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/cache/NullCacheProvider.java
@@ -0,0 +1,7 @@
+package com.scientiamobile.wurfl.core.cache;
+
+public class NullCacheProvider implements CacheProvider {
+
+ public NullCacheProvider() {
+ }
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/CapabilityNotDefinedException.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/CapabilityNotDefinedException.java
new file mode 100644
index 00000000000..64c6ca4393d
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/CapabilityNotDefinedException.java
@@ -0,0 +1,12 @@
+package com.scientiamobile.wurfl.core.exc;
+
+public class CapabilityNotDefinedException extends WURFLRuntimeException {
+
+ public CapabilityNotDefinedException(String message) {
+ super(message);
+ }
+
+ public CapabilityNotDefinedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/VirtualCapabilityNotDefinedException.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/VirtualCapabilityNotDefinedException.java
new file mode 100644
index 00000000000..0dd80b37bb7
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/VirtualCapabilityNotDefinedException.java
@@ -0,0 +1,12 @@
+package com.scientiamobile.wurfl.core.exc;
+
+public class VirtualCapabilityNotDefinedException extends WURFLRuntimeException {
+
+ public VirtualCapabilityNotDefinedException(String message) {
+ super(message);
+ }
+
+ public VirtualCapabilityNotDefinedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/WURFLRuntimeException.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/WURFLRuntimeException.java
new file mode 100644
index 00000000000..6e20e217a1d
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/exc/WURFLRuntimeException.java
@@ -0,0 +1,12 @@
+package com.scientiamobile.wurfl.core.exc;
+
+public class WURFLRuntimeException extends RuntimeException {
+
+ public WURFLRuntimeException(String message) {
+ super(message);
+ }
+
+ public WURFLRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/matchers/MatchType.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/matchers/MatchType.java
new file mode 100644
index 00000000000..dcb55fc2020
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/matchers/MatchType.java
@@ -0,0 +1,7 @@
+package com.scientiamobile.wurfl.core.matchers;
+
+public enum MatchType {
+
+ conclusive,
+ recovery
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/updater/Frequency.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/updater/Frequency.java
new file mode 100644
index 00000000000..1d088d2832d
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/updater/Frequency.java
@@ -0,0 +1,7 @@
+package com.scientiamobile.wurfl.core.updater;
+
+public enum Frequency {
+
+ DAILY,
+ WEEKLY
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/updater/WURFLUpdater.java b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/updater/WURFLUpdater.java
new file mode 100644
index 00000000000..2fe046f1ed3
--- /dev/null
+++ b/extra/modules/WURFL-devicedetection/src/main/java/com/scientiamobile/wurfl/core/updater/WURFLUpdater.java
@@ -0,0 +1,11 @@
+package com.scientiamobile.wurfl.core.updater;
+
+import com.scientiamobile.wurfl.core.WURFLEngine;
+
+public class WURFLUpdater {
+
+ public WURFLUpdater(WURFLEngine engine, String wurflFileUrl){}
+
+ public void setFrequency(Frequency frequency){ }
+ public void performPeriodicUpdate(){}
+}
diff --git a/extra/modules/WURFL-devicedetection/src/main/resources/module-config/WURFL-devicedetection.yaml b/extra/modules/WURFL-devicedetection/src/main/resources/module-config/WURFL-devicedetection.yaml
index e8c4f2a5229..73fe089d34c 100644
--- a/extra/modules/WURFL-devicedetection/src/main/resources/module-config/WURFL-devicedetection.yaml
+++ b/extra/modules/WURFL-devicedetection/src/main/resources/module-config/WURFL-devicedetection.yaml
@@ -39,7 +39,7 @@ hooks:
modules:
wurfl-devicedetection:
wurfl-file-dir-path:
- wurfl-snapshot-url: https://data.scientiamobile.com//wurfl.zip
+ wurfl-snapshot-url: https://data.scientiamobile.com/your_wurfl_snapshot_url/wurfl.zip
cache-size: 200000
wurfl-run-updater: true
allowed-publisher-ids: 1
diff --git a/extra/modules/WURFL-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/mock/WURFLDeviceMock.java b/extra/modules/WURFL-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/mock/WURFLDeviceMock.java
index a3280fe7d42..fd2a0bc820e 100644
--- a/extra/modules/WURFL-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/mock/WURFLDeviceMock.java
+++ b/extra/modules/WURFL-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/mock/WURFLDeviceMock.java
@@ -48,17 +48,11 @@ public boolean getVirtualCapabilityAsBool(String vcapName) throws VirtualCapabil
return false;
}
- @Override
- public Map getVirtualCapabilities() {
- return Map.of();
- }
-
@Override
public String getId() {
return id;
}
- @Override
public String getWURFLUserAgent() {
return "";
}
@@ -91,17 +85,18 @@ public boolean getCapabilityAsBool(String capName) throws CapabilityNotDefinedEx
};
}
- @Override
public Map getCapabilities() {
return Map.of();
}
- @Override
+ public Map getVirtualCapabilities() {
+ return Map.of();
+ }
+
public boolean isActualDeviceRoot() {
return true;
}
- @Override
public String getDeviceRootId() {
return "";
}
diff --git a/extra/modules/pom.xml b/extra/modules/pom.xml
index fc67f358805..04d49f64886 100644
--- a/extra/modules/pom.xml
+++ b/extra/modules/pom.xml
@@ -24,7 +24,7 @@
pb-response-correction
greenbids-real-time-data
pb-request-correction
-
+ WURFL-devicedetection