Java User-Agent detector and caching

It’s often important for a server side application to understand the client platform. There are two common methods used for this.

  1. On the client itself, “capabilities” can be tested.
  2. Unfortunately, the server cannot easily test these, and as such must usually rely upon the HTTP Header information, notably “User-Agent”.

Example User-agent might typically look like this for a common desktop browser, developers can usually determine the platform without a lot of work.

"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)"

Determining robots and mobile platforms, unfortunately is a lot more difficult due to the variations. Libraries as those described below simplify this work as standard Java Objects expose the attributes that are commonly expected.

With Maven, the dependencies are all resolved with the following POM addition:

<dependency>
<groupid>net.sf.uadetector</groupid>
<artifactid>uadetector-resources</artifactid>
<version>2014.10</version>
</dependency>


/* Get an UserAgentStringParser and analyze the requesting client */
final UserAgentStringParser parser = UADetectorServiceFactory.getResourceModuleParser();
final ReadableUserAgent agent = parser.parse(request.getHeader("User-Agent"));

out.append("You're a '");
out.append(agent.getName());
out.append("' on '");
out.append(agent.getOperatingSystem().getName());
out.append("'.");

As indicated on the website documentation, running this query for each request uses valuable server resources, it’s best to cache the responses to minimize the impact!

http://uadetector.sourceforge.net/usage.html#improve_performance

NOTE: the website caching example is hard to copy-paste, here’s a cleaner copy.


/*
* COPYRIGHT.
*/
package com.example.cache;

import java.util.concurrent.TimeUnit;
import net.sf.uadetector.ReadableUserAgent;
import net.sf.uadetector.UserAgentStringParser;
import net.sf.uadetector.service.UADetectorServiceFactory;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

/**
* Caching User Agent parser
* @see http://uadetector.sourceforge.net/usage.html#improve_performance
* @author Scott Fredrickson [skotfred]
* @since 2015jan28
* @version 2015jan28
*/
public final class CachedUserAgentStringParser implements UserAgentStringParser {

private final UserAgentStringParser parser = UADetectorServiceFactory.getCachingAndUpdatingParser();
private static final int CACHE_MAX_SIZE = 100;
private static final int CACHE_MAX_HOURS = 2;
/**
* Limited to 100 elements for 2 hours!
*/
private final Cache<String , ReadableUserAgent> cache = CacheBuilder.newBuilder().maximumSize(CACHE_MAX_SIZE).expireAfterWrite(CACHE_MAX_HOURS, TimeUnit.HOURS).build();

/**
* @return {@code String}
*/
@Override
public String getDataVersion() {
return parser.getDataVersion();
}
/**
* @param userAgentString {@code String}
* @return {@link ReadableUserAgent}
*/
@Override
public ReadableUserAgent parse(final String userAgentString) {
ReadableUserAgent result = cache.getIfPresent(userAgentString);
if (result == null) {
result = parser.parse(userAgentString);
cache.put(userAgentString, result);
}
return result;
}
/**
*
*/
@Override
public void shutdown() {
parser.shutdown();
}
}

REFERENCES:

Adding meta “viewport” for WordPress

Google recently changed their search algoritms to better recognize and weight “Mobile” support. This term is loosely defined in general, but to get your Google search “juice” you simply need to add a “viewport” meta tag. Unfortunately, unless you have the knowledge and want to edit your WordPress theme manually, there’s not an obvious way to add this.

Adding the “Definitely Allow Mobile Zooming” plugin makes this painless in WordPress without any additional configuration.

HTML code required (in <head>):

<meta name="viewport" content="width=device-width" />

PHP required (for manual addition):

<?php
function set_viewport() {
?>
<meta name="viewport" content="width=device-width" />
<?php
}
add_action('wp_head', 'set_viewport');
?>

REFERENCES:

meta viewport minimal-ui… a good idea in it’s time, just not useable…

Apple added this capability for fullscreen browser applications in Safari for IOS 7.1, unfortunately, they removed it in IOS 8.0


<meta name="viewport" content="width=device-width, minimal-ui" />

REFERENCES:

Preventing Blackberry browser from messing up your UI

I’ve previously given steps to prevent phone numbers (and other elements) from being automatically reformatted by Skype Toolbar and IOS Safari, there is still a small segment of the user population that uses Blackberry devices that can similarly benefit from a little code.

The following stops auto detection and formatting of phone and email addresses on devices with the BlackBerry Browser.

HTML:

<meta http-equiv="x-rim-auto-match" content="none" />

WML:

<meta name="x-rim-auto-match" http-equiv="x-rim-auto-match" forua="true" content="none" />

REFERENCES:

HTML cleartype meta tag?

This tag allows for activation of ClearType in Mobile IE for smoothing fonts.


<!--[if IEMobile]><meta http-equiv="cleartype" content="on" /><![endif]-->

NOTE: Future use of this approach is questionable, as MSIE10 dropped support of conditional comments, and HTML5 validators (in general) do not “like” the http-equiv values as they are not standardized

REFERENCES:

Preventing IOS/Safari from formatting numbers

There are many cases where your application may display numbers that “resemble” phone numbers, but are not, unfortunately Safari’s default behavior is for it to be “helpful” and format them into clickable/callable links for the user of Apple IOS devices.

Adding the following META tag can prevent that default behavior:

<meta name="format-detection" content="telephone=no" />
.

NOTE: I’ve seen some mention of using this method for ‘address=no’ and ’email=no’, but have not looked into or verified those implementation yet!

REFERENCES:

CSS media queries for landscape vs. portrait orientation

As mobile devices become more prevalent in the web development domain, it is often advisable to provide appropriate CSS for each layout.

Here’s a starting point for browsers that support.


<style type="text/css">
@media all and (orientation:portrait) {
/* css adjustments for portrait go here */
}
@media all and (orientation:landscape) {
/* css adjustments for landscape go here */
}
</style>

Enable Sharing of Printers via Apple AirPrint

This is relevant only after you have updated to Apple IOS 4.2.x on your iPhone, iPod Touch or iPad device. With this release, the ability to print has been added, but it takes a bit of configuration to setup the printer sharing itself as it relies on the Apple Bonjour service/protocol!

I assume that this is all trivial if you are using a networked printer, particularly if it’s wireless…. but if you have a printer that is shared by another computer on the network, you’ll have to do the following.

  1. Install iTunes 10.1 (or newer) on the PC
  2. Install IOS 4.2.1 (or newer) on the mobile device
  3. Download AirPrint.zip (airprint.exe, libairprint.dll, XpdfPrint.dll)
  4. Unzip it.
  5. Make a folder, “C:\Program Files (x86)\AirPrint\” (NOTE: without the x86 for 32bit)
  6. Copy the files to “C:\Program Files (x86)\AirPrint\” (NOTE: without the x86 for 32bit)
  7. Run “cmd.exe” as administrator
  8. Run the following commands (There should be a space between ‘=’ and ‘”‘)
    • Windows 64bits:
      sc.exe create AirPrint binPath= "C:\Program Files (x86)\AirPrint\airprint.exe -s" depend= "Bonjour Service" start= auto
      sc.exe start AirPrint
    • Windows 32bits:
      sc.exe create AirPrint binPath= "C:\Program Files\AirPrint\airprint.exe -s" depend= "Bonjour Service" start= auto
      sc.exe start AirPrint
  9. Let Windows Firewall allow AirPrint to communicate on the networks (Double click on the airprint.exe)
  10. Now, open Safari or any other printing application on your device and try to Print, the first time will have to select the printer, and you may need to give user credentials for the printer.

REFERENCES:

Cheers!