Web content delivered to mobile devices can benefit from being tailored to take into account a range of factors such as screen size, markup language support and image format support. Such information is stored in “Device Description Repositories” (DDRs).
Until recently WURFL was the de facto DDR standard for mobile capabilities, but its license changed to AGPL (Affero GPL) v3, meaning it is not free to be used commercially anymore. Consequently some free open source alternatives to WURFL have recently started to show up and are improving quickly.
OpenDDR and 51Degrees.mobi are candidate substitutes to WURFL that also provide an API to access DDRs.
These tools ease and promote the development of Web content that adapts to its delivery context. This post summarizes the installation and configuration of these tools and analyzes how they compare in terms of image adaptation.
Build configuration
This section describes how to add the dependencies to a Maven project.
WURFL
WURFL is really straightforward since it is available on Maven central repository. All you have to do is to include the dependency on your project:
<dependency>
<groupId>net.sourceforge.wurfl</groupId>
<artifactId>wurfl</artifactId>
<version>1.2.2</version><!-- the latest free version -->
</dependency>
OpenDDR
OpenDDR is a bit harder to configure. Follow these steps to include OpenDDR in your project:
- Download OpenDDR-Simple-API zip package and unzip it.
-
From the resulting folder, install
bin/OpenDDR-Simple-API-1.0.0.10.jarandlib/DDR-Simple-API.jarinto your local Maven repository:mvn install:install-file -DgroupId=org.w3c.ddr.simple -DartifactId=DDR-Simple-API -Dversion=2008-03-30 -Dpackaging=jar -Dfile=DDR-Simple-API.jar -DgeneratePom=true -DcreateChecksum=true mvn install:install-file -DgroupId=org.openddr.simpleapi.oddr -DartifactId=OpenDDR-Simple-API -Dversion=1.0.0.10 -Dpackaging=jar -Dfile=OpenDDR-Simple-API-1.0.0.10.jar -DgeneratePom=true -DcreateChecksum=true
-
Add the dependencies to your project
pom.xmlfile:<dependency> <groupId>org.w3c.ddr.simple</groupId> <artifactId>DDR-Simple-API</artifactId> <version>2008-03-30</version> </dependency> <dependency> <groupId>org.openddr.simpleapi.oddr</groupId> <artifactId>OpenDDR-Simple-API</artifactId> <version>1.0.0.10</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-jexl</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency>
51Degrees.mobi
51Degrees.mobi is similar to OpenDDR but with fewer dependencies to install:
- Download 51Degrees.mobi-Java zip package and unzip it.
-
From the resulting folder, install
dist/51Degrees.mobi.detection.jarinto your local Maven repository:mvn install:install-file -DgroupId=mobi.51degrees -DartifactId=detection -Dversion=2.1.15.1 -Dpackaging=jar -Dfile=51Degrees.mobi.detection.jar -DgeneratePom=true -DcreateChecksum=true
-
Add the dependencies to your project
pom.xmlfile:<dependency> <groupId>mobi.51degrees</groupId> <artifactId>detection</artifactId> <version>2.1.15.1</version> </dependency>
Loading repository/capabilities file
This section describes how to load repository files and import them into your project.
WURFL
Copy wurfl-2.1.1.xml.gz file (the latest free version) into your project src/main/resources folder and import it using:
WURFLHolder wurflHolder = new CustomWURFLHolder(getClass().getResource("/wurfl-2.1.1.xml.gz").toString());
OpenDDR
Copy oddr.properties from the OpenDDR-Simple-API src folder and all files inside OpenDDR-Simple-API resources folder into your project src/main/resources folder. Import them using:
Service identificationService = null;
try {
Properties initializationProperties = new Properties();
initializationProperties.load(getClass().getResourceAsStream("/oddr.properties"));
identificationService = ServiceFactory
.newService("org.openddr.simpleapi.oddr.ODDRService",
initializationProperties.getProperty(ODDRService.ODDR_VOCABULARY_IRI),
initializationProperties);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
} catch (InitializationException e) {
LOGGER.error(e.getMessage(), e);
} catch (NameException e) {
LOGGER.error(e.getMessage(), e);
}
51Degrees.mobi
51Degrees.mobi does not use a separate repository file.
Using the API
This section describes how use WURFL and OpenDDR Java APIs to access the device capabilities.
WURFL
WURFL API is very easy to use and has the greatest advantage of providing a powerful fallback hierarchy, inferring capabilities for devices not yet in its repository file.
Device device = wurflHolder.getWURFLManager().getDeviceForRequest(getContext().getRequest());
int resolutionWidth = Integer.valueOf(device.getCapability("resolution_width"));
int resolutionHeight = Integer.valueOf(device.getCapability("resolution_height"));
There’s no need to validate device.getCapability("resolution_width") against null value when no data is available.
OpenDDR
OpenDDR API is very cumbersome. It does not have a fallback hierarchy, instead it assumes 800px as the default value for displayWidth and 600px as the default value for displayHeight.
PropertyRef displayWidthRef;
PropertyRef displayHeightRef;
try {
displayWidthRef = identificationService.newPropertyRef("displayWidth");
displayHeightRef = identificationService.newPropertyRef("displayHeight");
} catch (NameException e) {
throw new RuntimeException(e);
}
PropertyRef[] propertyRefs = new PropertyRef[] { displayWidthRef, displayHeightRef };
Evidence evidence = new ODDRHTTPEvidence();
evidence.put("User-Agent", getContext().getRequest().getHeader("User-Agent"));
int displayWidth = 320; // Default value
int displayHeight = 480; // Default value
try {
PropertyValues propertyValues = identificationService.getPropertyValues(evidence, propertyRefs);
PropertyValue displayWidthProperty = propertyValues.getValue(displayWidthRef);
PropertyValue displayHeightProperty = propertyValues.getValue(displayHeightRef);
if (displayWidthProperty.exists()) { // Don't really need to validate. Returns 800 as the default value.
displayWidth= displayWidthProperty.getInteger();
}
if (displayHeightProperty .exists()) { // Don't really need to validate. Returns 600 as the default value.
displayHeight = displayHeightProperty.getInteger();
}
} catch (NameException e) {
throw new RuntimeException(e);
} catch (ValueException e) {
throw new RuntimeException(e);
}
51Degrees.mobi
Similarly to OpenDDR, 51Degrees.mobi does not provide a fallback hierarchy. The developer must always validate each property value.
// Create a Provider object
Provider provider;
try {
provider = Reader.create();
} catch (BinaryException e) {
throw new RuntimeException(e);
}
// Read in a HttpServletRequest or User Agent String
BaseDeviceInfo deviceInfo = provider.getDeviceInfo(request.getHeader("User-Agent"));
// Get the value of a property
Integer screenPixelsWidth = 320; // Default value
Integer screenPixelsHeight = 480; // Default value
try {
screenPixelsWidth = Integer.valueOf(deviceInfo.getFirstPropertyValue("ScreenPixelsWidth"));
} catch (NumberFormatException e) {
}
try {
screenPixelsHeight = Integer.valueOf(deviceInfo.getFirstPropertyValue("ScreenPixelsHeight"));
} catch (NumberFormatException e) {
}
// Before exiting your application, ensure you dispose of the Provide to
// release it's resources such as it's thread pool
provider.destroy();
Results
The following table shows the results of the tests run against an application for server-side image adaptation. The tests were performed on real physical devices.
| Platform | Device | Property | WURFL max_image_width (1) / max_image_height |
WURFL resolution_width / resolution_height |
OpenDDR displayWidth / displayHeight |
51Degrees.mobi ScreenPixelsWidth / ScreenPixelsHeight |
|---|---|---|---|---|---|---|
| Windows | Firefox desktop | width | 600 | 640 | 800 | Unknown |
| height | 600 | 480 | 600 | Unknown | ||
| iOS | iPhone 4S | width | 320 | 320 | 320 | 320 |
| height | 480 | 480 | 480 | 480 | ||
| Android | Samsung Galaxy S II | width | 240 | 240 | 480 | 480 |
| height | 320 | 320 | 800 | 800 | ||
| HTC One V | width | 600 | 640 | 480 | 480 | |
| height | 600 | 480 | 800 | 800 | ||
| HTC Hero | width | 300 | 320 | 320 | 320 | |
| height | 460 | 480 | 480 | 480 | ||
| Windows Phone 7.5 | Nokia Lumia 710 | width | 600 | 640 | 480 | 480 |
| height | 600 | 480 | 800 | 800 | ||
| BlackBerry | BlackBerry Bold 9900 | width | 228 | 480 | 640 | 640 |
| height | 280 | 640 | 480 | 480 | ||
| Symbian S60 | Nokia E52 (Webkit) | width | 234 | 240 | 240 | 240 |
| height | 280 | 320 | 320 | 320 | ||
| Nokia E52 (Opera Mobile) | width | 240 | 240 | 800 | Unknown | |
| height | 280 | 320 | 600 | Unknown | ||
| Bada 2.0 | Samsung Wave 3 | width | 600 | 640 | 480 | 480 |
| height | 600 | 480 | 800 | 800 | ||
| Windows Mobile 6.1 | HTC Touch HD T8282 | width | 440 | 480 | 480 | 480 |
| height | 700 | 800 | 800 | 800 |
(1) max_image_width capability is very handy:
Width of the images viewable (usable) width expressed in pixels. This capability refers to the image when used in “mobile mode”, i.e. when the page is served as XHTML MP, or it uses meta-tags such as “viewport”, “handheldfriendly”, “mobileoptimised” to disable “web rendering” and force a mobile user-experience.
Note: The color #9f9 highlights the results that performed better and #f99 highlights the results that performed worse.
Feel free to run the tests for yourself, the source code used for this article is available on GitHub and is licensed under the Apache License, Version 2.0.
Pros and Cons
| Pros | Cons | |
|---|---|---|
| WURFL |
|
|
| OpenDDR |
|
|
| 51Degrees.mobi |
|
|
Let me stress how advantageous is to be able to upgrade WURFL by just replacing its XML database file. For the changes to take effect, there is no need to restart the application server or change the application source code. WURFL is also the only one supporting Opera Mobile browser.
Ending note
Keep in mind that while OpenDDR and 51Degrees.mobi test results may improve over time as I update the tests to use newer versions of them, WURFL will not be updated due to its new restrictive license. However, if a DDR solution is crucial to your business, you should really consider new versions of WURFL. It has improved a lot since the version used in this post making it probably the best DDR money can buy.
Thank you for including 51Degrees.mobi in your comparison. The following may assist the reader understand a little more about the 51Degrees.mobi approach.
Properties are maintained by a 51Degrees.mobi team of professionals who work to consistent quality standards. ScreenPixelsWidth and Height represent the size of screen in pixels if known. We have 50 properties in the free Lite data, and over 100 properties in the Premium data. We deliberately decided not to include some capabilities. For example; i-mode support and WML support. We do receive requests for new properties, a recent example being the inclusion of Ringmark browser properties to provide a server side alternative to Modernizr. What properties/capabilities would readers like to see included?
The Java API can optionally be passed a data file when the provider is constructed.
Provider p = Reader.create(“PATH_TO_DATA_FILE”);
New data files are published monthly on Codeplex, or weekly if a Premium data file is purchased. If a data file is not provided the embedded one is used.
Hi, Luca Passani, creator of WURFL and ScientiaMobile CTO, here.
Thank you for reporting about WURFL in your article.
WURFL was created in 2001 and has laid the way for virtually all other DDRs that have copied it conceptually or in more consistent (and arguably not always legitimate) ways (I don’t want to digress…).
WURFL moved to the AGPL license last year to make the economic model behind it sustainable and bring more better Device Detection to developers, while, at the same time, making sure that small shops and hobbysts could still benefit from the product (among other things, we have a free of charge WURFL Cloud offering).
Apart from the grumbling of some open-source zealots, everyone agrees that this was a positive move for the product and for the support that ScientiaMobile is now able to offer WURFL adopters at a reasonable cost.
A clear example of the advantage of the new WURFL is ScientiaMobile’s ability to deliver new products in the DDR space. This week, we launched WURFL Modules for Varnish-Cache, NGINX and Apache.
These will enable developers to do things like:
// PHP
if ($_SERVER['HTTP_X_WURFL_IS_TABLET'] == ‘true’) {
//Do whatever makes sense for a tablet
}
without the need to install the WURFL libraries as part of the application itself,
More info (and more use-cases) can be found here:
http://www.scientiamobile.com/blog/post/view/id/25/title/WURFL-with-Varnish-Cache-Apache-and-NGINX
Thank you
Luca Passani
CTO @ScientiaMobile
Sam,
Thank you for the technically motivated and vendor-neutral view on 3 popular Device Description Repositories including OpenDDR. And for providing the test Open Source on GitHub, where OpenDDR is also maintained.
I can confirm, compatibility with W3C DDR has been a driving factor behind OpenDDR so far, which explains some of the results or differences you mention. OpenDDR can be both configured and where necessary extended/patched very easily. You mention the oddr.properties, but without having looked at your example code, the threshold value in the properties file can or needs to be adjusted allowing to tweak precision of findings over other factors like memory consumption. Tests against the latest available and free WURFL showed, that while it produces results similar to what you observed, its memory consumption in a similar setup are up to 500MB where a full scale OpenDDR (full W3C DDR vocabulary) required no more than 100MB, with a limited vocabulary even as low as 50MB. Did you do any tests in that direction?
I haven’t personally looked at the footprint of 51Degrees.mobi but given it uses a different approach and does not claim to be W3C DDR compatible either, it may have a memory footprint as good or below OpenDDR.
Especially if you host your solutions in the Cloud, not just storage but other behavior of your application is measured and may be charged for, too. Not just the different pricing of the actual DDR solutions you outlined rather accurately.
Let me add, that OpenDDR has been contributed to Apache DeviceMap as of last week and there may be different strategies for e.g. the mentioned fallback if enough members of the Apache community demand that or contribute to. Please keep an eye on the DeviceMap project. Like some of its siblings, especially client-side Device Recognition and cross-scripting Cordova (contributed by Phonegap) or OpenOffice, incubation may take time, so do license-adjustments (to Apache License, don’t worry, it’ll rather get more open in our case;-) but expect to get your hands on it no later than early next year. DeviceMap will be fully backward-compatible with OpenDDR, both API and resource files, while over time, it may add features or capabilities the community wishes to see.
Thanks and Regards,
Werner Keil | Principal Community Evangelist | OpenDDR
I need to get back on this to state that the numbers reported by Werner Keil about the performance of the WURFL API are incorrect.
The WURFL API can be configured to use only a subset of the capabilities and to use different caching mechanisms (through Spring Framework configuration).
Most WURFL Java installations have a memory usage <50Mb.
Of course, as Albert Einstein used to say, make things simple, as simple as possible, but not simpler. Today's mobile devices go out of their way to camouflage and WURFL adds just enough complexity to stay on top of the problem.
Of course, in addition to Java, WURFL has APIs for all platforms (even Perl, Ruby, Python and Node.js, if the WURFL Cloud is accounted for). This addresses the needs of all companies, from small shops to large organizations that need scalability and reliability.
The W3C recommendation quoted by Keil has been totally ignored by the industry for many years. OpenDDR reverted to it in the attempt to copy from WURFL while trying to avoid the liability that comes from it.
Luca Passani
CTO @ScientiaMobile
Thank you all for your feedback and clarification.
@James: For new features we would like to see in next versions, I would like very much to have support for Opera Mobile.
Another solution could be my open source project called Apache Mobile Filter.org.
Over 16000 in 5 years and completely free
http://www.apachemobilefilter.org