» FasterDDR
welcome
Welcome to the FasterDDR open source project. The project provides read/write and refactor/caching interfaces to WURFL and OpenDDR (experimental) XML files and is written in Java.
overview
The most important features of this project are
- * Lightweight
- * Easy to use - few and simple interfaces
- * Efficient - fast setup and usage
FasterDDR is helpful for CPU- and memory-constrained environments which need access to the WURFL capabilities.
reading
Reading capabilities is straightforward:
// create device repository factory DDRFactory ddrFactory = new WurflFactory(); // create repository instance DDR ddr = ddrFactory.newInstance(new File("wurfl.xml"), "UTF-8"); // add patch file ddrFactory.parsePatch(ddr, new File("wurfl_patch.xml"), "UTF-8"); // get a device using its id Device device = ddr.getCapabilityDevice("nokia_n95_ver1"); // get the bandwidth as a string String bandwidthString = device.getStringCapability("max_data_rate"); |
Alternatively, use one of the convenience methods:
// get the bandwidth as a long with a default value fallback long bandwidth = device.getLongCapability("max_data_rate", -1L); |
Note that zero-length strings ("") returns as null.
writing
Slashing the capabilities you do not need can save a lot of memory, given the DOM-nature of most DDR-APIs.
// get the device description repository and output stream DDR ddr = getDDR(); OutputStream = getOutputStream(); // get serializer WurflSerializer serializer = new WurflSerializer(); // add group serializer.addGroup("object_download"); // add capability to group serializer.addCapability("object_download", "video_mov"); // add another group serializer.addGroup("display"); // add capability to group serializer.addCapability("display", "max_image_width"); // serialize serializer.serialize(ddr, out); |
In addition, it is also possible to add a device filter to remove devices you do not need.
refactoring
Refactoring device description repository files can potentially reduce the size of the output XML file further.
// get the device description repository DDR ddr = getDDR(); // create a set of the desired output capabilities Set |
Refactoring reorganizes the device hierarchy, but keeps everything else intact, like device id, user-agent and capability values.
Refactoring should be performed offline, and patches must be incorporated first. Again, a device filter can also used.
example results
Refactoring the capabilities found within each WURFL group, the following reductions were made:
Group name | Capabilities | Before | After | Change |
---|---|---|---|---|
ajax | 9 | 2098 KB | 2259 KB | -8 % |
bearer | 5 | 2192 KB | 2545 KB | -14 % |
bugs | 4 | 2095 KB | 2196 KB | -5 % |
cache | 2 | 2105 KB | 2196 KB | -5 % |
chtml_ui | 7 | 2070 KB | 2198 KB | -6 % |
css | 5 | 2109 KB | 2251 KB | -7 % |
display | 9 | 2595 KB | 4079 KB | -37 % |
drm | 3 | 2149 KB | 2373 KB | -10 % |
flash_lite | 7 | 2093 KB | 2354 KB | -12 % |
html_ui | 11 | 2120 KB | 2225 KB | -5 % |
image_format | 14 | 2231 KB | 3190 KB | -31 % |
j2me | 77 | 2275 KB | 2874 KB | -21 % |
markup | 19 | 2259 KB | 2754 KB | -18 % |
mms | 44 | 2298 KB | 4239 KB | -46 % |
object_download | 79 | 2680 KB | 4011 KB | -34 % |
1 | 2072 KB | 2206 KB | -7 % | |
playback | 20 | 2189 KB | 2757 KB | -21 % |
product_info | 19 | 2564 KB | 2953 KB | -14 % |
rss | 1 | 2061 KB | 2199 KB | -7 % |
security | 2 | 2053 KB | 2197 KB | -7 % |
sms | 29 | 2140 KB | 2222 KB | -4 % |
sound_format | 21 | 2255 KB | 3167 KB | -29 % |
storage | 10 | 2256 KB | 2465 KB | -9 % |
streaming | 17 | 2209 KB | 2898 KB | -24 % |
transcoding | 2 | 2054 KB | 2196 KB | -7 % |
wap_push | 14 | 2190 KB | 2539 KB | -14 % |
wml_ui | 22 | 2186 KB | 2517 KB | -14 % |
wta | 5 | 2156 KB | 2425 KB | -12 % |
xhtml_ui | 34 | 2259 KB | 2381 KB | -6 % |
Note that: Results will vary depending on which capabilities you include - as with all optimizations, care should be taken in
verification of the actual improvement.
caching
The project also includes a simple cache filter which helps in populating a delegate cache provided by you. It organizes
devices which do not specify their own capabilities in sets with their parent(s). As one device is assigned a value,
all members in the same set are assigned that value too.
// get the device description repository DDR ddr = getDDR(); // get your usual cache from somewhere, for your custom value V CacheProvider<String, V> cacheDelegate = getCache(); // create the cache factory DDREmptyDescendantCacheFactory factory = new DDREmptyDescendantCacheFactory(ddr); // get a cache instance EmptyDescendantCache<V> cache = factory.newEmptyDescendantCache(cacheDelegate); // as a request is processed, check cache for some device id V value = cache.get("nokia_n95_ver1"); if(value == null) { // no value is cached // generate a new value value = createValue("nokia_n95_ver1"); // add value to cache cache.put("nokia_n95_ver1", value); // populates all devices in the same groups as nokia_n95_ver1 } // .. use value in request response |
In other words
cache.put("nokia_n95_ver1", value); |
can later yield a positive result for
V value = cache.get("nokia_n93_ver1"); |
if the two devices are in the same set. Use a cache delegate wrapper if you want to use a more structured or complicated
key in your actual backend cache, i.e. for example go from 'nokia_n95_ver1' to '/items/54/nokia_n95_ver1'.
The cache is light-weight and suitable as part of for example EAR or WAR deployment initializations.
There is also a version of this cache for use with the latest WURFL API.
combining cache and refactoring - example results
Refactoring typically increases the number of empty devices, thus adding to the cache effectiveness.
The following tables shows cache statistics before and after refactoring, again for each WURFL group:
Sets | Empty devices | Requests | ||||
---|---|---|---|---|---|---|
Group | Before | After | Before | After | Before | After |
ajax | 124 | 22 | 6555 | 6679 | 172 | 15 |
bearer | 492 | 28 | 4652 | 6672 | 8254 | 32 |
bugs | 2 | 2 | 6684 | 6686 | 5 | 5 |
cache | 5 | 3 | 6681 | 6685 | 4 | 4 |
chtml_ui | 10 | 6 | 6680 | 6683 | 16 | 7 |
css | 227 | 7 | 6116 | 6684 | 1712 | 12 |
display | 1115 | 1156 | 1276 | 4740 | 13994 | 10054 |
drm | 453 | 8 | 5456 | 6682 | 5127 | 12 |
flash_lite | 238 | 36 | 5666 | 6662 | 4223 | 42 |
html_ui | 100 | 20 | 6490 | 6678 | 120 | 22 |
image_format | 973 | 133 | 2873 | 6580 | 11681 | 248 |
j2me | 776 | 291 | 4493 | 6463 | 8308 | 921 |
markup | 598 | 167 | 3754 | 6563 | 10193 | 349 |
mms | 637 | 490 | 4171 | 6084 | 9094 | 3518 |
object_download | 974 | 726 | 3441 | 5674 | 10743 | 6876 |
70 | 2 | 6563 | 6686 | 21 | 1 | |
playback | 581 | 187 | 4981 | 6548 | 6950 | 344 |
rss | 33 | 2 | 6646 | 6686 | 1 | 1 |
security | 14 | 2 | 6669 | 6686 | 17 | 1 |
sms | 156 | 21 | 6442 | 6672 | 107 | 15 |
sound_format | 913 | 416 | 3478 | 6384 | 10556 | 1696 |
storage | 689 | 182 | 4190 | 6564 | 9058 | 358 |
streaming | 1077 | 218 | 1910 | 6516 | 13240 | 454 |
transcoding | 3 | 3 | 6686 | 6685 | 1 | 1 |
wap_push | 474 | 51 | 4619 | 6651 | 8113 | 39 |
wml_ui | 416 | 29 | 4583 | 6670 | 8188 | 26 |
wta | 393 | 9 | 5046 | 6682 | 6711 | 14 |
xhtml_ui | 371 | 155 | 5755 | 6587 | 3858 | 229 |
Again note that: Results will vary depending on which capabilities you include.
The most important number in the above table is the estimated number of (random, uniformly distributed) requests for (6686 root) devices
required to fill 90% of the cache, before and after refactoring. Refactoring makes the number of empty (root) devices
increase and thus the number of sets go down correspondingly. Then the cache is likely to be populated with fewer requests,
increasing hit rates and so increasing performance.
other features
We managed to squeeze in a few extra essential features:
- * Read access thread safety
- * Compressed device states
- * Optional String internating
See the javadoc for additional documentation.
license
The FasterDDR library is released under the MIT license.
feedback
Please tell us what you think! Use the forums or mailing lists. All feedback is valuable.