- Replace Browser user agent detection

This commit is contained in:
Paulo Gustavo Veiga 2012-09-16 18:36:23 -03:00
parent f90dd4f22a
commit 36a35b44d7
16 changed files with 1837 additions and 452 deletions

View File

@ -1,76 +1,76 @@
/* /*
* Copyright [2011] [wisemapping] * Copyright [2011] [wisemapping]
* *
* Licensed under WiseMapping Public License, Version 1.0 (the "License"). * Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the * It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page; * "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the license at * You may obtain a copy of the license at
* *
* http://www.wisemapping.org/license * http://www.wisemapping.org/license
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.wisemapping.filter; package com.wisemapping.filter;
import com.wisemapping.exceptions.GoogleChromeFrameRequiredException; import com.wisemapping.exceptions.GoogleChromeFrameRequiredException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import com.wisemapping.exceptions.UnsupportedBrowserException; import com.wisemapping.exceptions.UnsupportedBrowserException;
import java.util.Set; import java.util.Set;
public class BrowserSupportInterceptor extends HandlerInterceptorAdapter { public class BrowserSupportInterceptor extends HandlerInterceptorAdapter {
private Set<String> exclude; private Set<String> exclude;
public static final String USER_AGENT = "wisemapping.userAgent"; public static final String USER_AGENT = "wisemapping.userAgent";
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object object) throws Exception { public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object object) throws Exception {
final String requestUri = request.getRequestURI(); final String requestUri = request.getRequestURI();
if (exclude != null && !exclude.contains(requestUri)) { if (exclude != null && !exclude.contains(requestUri)) {
final HttpSession session = request.getSession(false); final HttpSession session = request.getSession(false);
// Try to loaded from the request ... // Try to loaded from the request ...
UserAgent userAgent = null; WiseUserAgent userAgent = null;
if (session != null) { if (session != null) {
userAgent = (UserAgent) session.getAttribute(USER_AGENT); userAgent = (WiseUserAgent) session.getAttribute(USER_AGENT);
} }
// I could not loaded. I will create a new one... // I could not loaded. I will create a new one...
if (userAgent == null) { if (userAgent == null) {
userAgent = UserAgent.create(request); userAgent = WiseUserAgent.create(request);
if (session != null) { if (session != null) {
session.setAttribute(USER_AGENT, userAgent); session.setAttribute(USER_AGENT, userAgent);
} }
} }
// It's a supported browser ?. // It's a supported browser ?.
if (!userAgent.isBrowserSupported()) { if (!userAgent.isBrowserSupported()) {
throw new UnsupportedBrowserException(); throw new UnsupportedBrowserException();
} }
// Is a Explorer 9 or less without Google Chrome Frame ?. // Is a Explorer 9 or less without Google Chrome Frame ?.
if (userAgent.needsGCF()) { if (userAgent.needsGCF()) {
throw new GoogleChromeFrameRequiredException(); throw new GoogleChromeFrameRequiredException();
} }
} }
return true; return true;
} }
public void setExclude(Set<String> exclude) { public void setExclude(Set<String> exclude) {
this.exclude = exclude; this.exclude = exclude;
} }
} }

View File

@ -1,350 +0,0 @@
/*
* Copyright [2011] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.filter;
import org.apache.commons.logging.LogFactory;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
public class UserAgent implements Serializable {
public static final String USER_AGENT_HEADER = "User-Agent";
private int versionMajor = -1;
private int versionVariation = -1;
private Product product;
private OS os;
private final org.apache.commons.logging.Log logger = LogFactory.getLog(UserAgent.class.getName());
private boolean hasGCFInstalled = false;
public static void main(final String argv[]) {
UserAgent explorer = UserAgent.create("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
// UserAgent firefox = UserAgent.create("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050302 Firefox/0.9.6");
UserAgent safari = UserAgent.create("iCab/2.9.5 (Macintosh; U; PPC; Mac OS X)");
UserAgent opera = UserAgent.create("Opera/9.21 (Windows NT 5.1; U; en)");
UserAgent firefox = UserAgent.create("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050302 Firefox/1.9.6");
assert firefox.isBrowserSupported();
firefox = UserAgent.create("Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 Creative ZENcast v1.02.08 FirePHP/0.0.5.13");
assert firefox.isBrowserSupported();
firefox = UserAgent.create("Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12");
assert firefox.isBrowserSupported();
firefox = UserAgent.create("'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.7) Gecko/20070914 firefox 2.0'");
assert firefox.isBrowserSupported();
firefox = UserAgent.create("Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080129 Iceweasel/2.0.0.12 (Debian-2.0.0.12-0etch1)");
assert firefox.isBrowserSupported();
}
public boolean isVersionGreatedOrEqualThan(final int mayor, final int variation) {
return this.versionMajor > mayor || (mayor == this.versionMajor && this.versionVariation >= variation);
}
public boolean isVersionLessThan(final int mayor) {
return this.versionMajor < mayor;
}
public int getVersionMajor() {
return versionMajor;
}
public int getVersionVariation() {
return versionVariation;
}
public Product getProduct() {
return product;
}
public OS getOs() {
return os;
}
public enum Product {
EXPLORER, FIREFOX, CAMINO, NETSCAPE, OPERA, SAFARI, CHROME, KONQUEOR, KMELEON, MOZILLA, LYNX, ROBOT, WEB_CRAWLER
}
public enum OS {
WINDOWS, LINUX, MAC, KNOWN
}
private UserAgent(final String header) {
parse(header);
}
private void parse(String userAgentHeader) {
// Format ApplicationName/ApplicationVersion ();
try {
// Mediapartners-Google -> Add sense robot
if(userAgentHeader.equals("Mediapartners-Google")){
this.product = Product.WEB_CRAWLER;
return;
}
int detailStart = userAgentHeader.indexOf('(');
int detailEnd = userAgentHeader.indexOf(')');
// Parse base format = application (productDetails) productAddition
String application = userAgentHeader.substring(0, detailStart);
application = application.trim();
String productDetails = userAgentHeader.substring(detailStart + 1, detailEnd);
productDetails = productDetails.trim();
String productAddition = userAgentHeader.substring(detailEnd + 1, userAgentHeader.length());
productAddition = productAddition.trim();
this.os = parseOS(productDetails);
if (userAgentHeader.contains("Googlebot") ) {
//"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
this.product = Product.WEB_CRAWLER;
} else if (userAgentHeader.contains("MSIE")) {
// Explorer Browser : http://msdn2.microsoft.com/en-us/library/ms537503.aspx
// Format: Mozilla/MozVer (compatible; MSIE IEVer[; Provider]; Platform[; Extension]*) [Addition]
// SampleTest: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;)
// Parse version ...
int index = productDetails.indexOf("MSIE") + 4;
int lastIndex = productDetails.indexOf(';', index);
final String versionStr = productDetails.substring(index + 1, lastIndex);
parseVersion(versionStr);
// Explorer Parse ...
this.product = Product.EXPLORER;
this.hasGCFInstalled = productDetails.contains("chromeframe");
} else if (userAgentHeader.contains("iCab") || userAgentHeader.contains("Safari")) {
// Safari:
//Formats: Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1
//Chrome:
//Formats: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7"
String versionStr = "";
if (userAgentHeader.contains("Chrome")) {
this.product = Product.CHROME;
versionStr = userAgentHeader.substring(userAgentHeader.indexOf("Chrome") + 7, userAgentHeader.lastIndexOf(" "));
} else {
this.product = Product.SAFARI;
versionStr = userAgentHeader.substring(userAgentHeader.indexOf("Version") + 8, userAgentHeader.lastIndexOf(" "));
}
parseVersion(versionStr);
} else if (userAgentHeader.contains("Konqueror")) {
this.product = Product.KONQUEOR;
} else if (userAgentHeader.contains("KMeleon")) {
this.product = Product.KMELEON;
} else if (userAgentHeader.contains("Gecko")) {
// Firefox/Mozilla/Camino:
// Mozilla/MozVer (Platform; Security; SubPlatform; Language; rv:Revision[; Extension]*) Gecko/GeckVer [Product/ProdVer]
// SampleTest: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050302 Firefox/0.9.6
// Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 Creative ZENcast v1.02.08 FirePHP/0.0.5.13
// 'Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.12) Gecko/20050915'
// 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.7) Gecko/20070914 firefox 2.0'
// 'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20060601 Firefox/2.0.0.6 (Ubuntu-edgy)'
// 'Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12'
// "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080129 Iceweasel/2.0.0.12 (Debian-2.0.0.12-0etch1)
// Remove gecko string
// Debian Firefox is remamed to iceweasel.
productAddition = productAddition.replace("Iceweasel", "firefox");
productAddition = productAddition.substring(productAddition.indexOf(' ') + 1);
productAddition = productAddition.toLowerCase();
String prodDesc = null;
if (productAddition.contains("firefox")) {
this.product = Product.FIREFOX;
prodDesc = "firefox";
} else if (productAddition.contains("netscape")) {
this.product = Product.NETSCAPE;
prodDesc = "netscape";
} else if (productAddition.contains("camino")) {
this.product = Product.CAMINO;
prodDesc = "camino";
} else {
this.product = Product.MOZILLA;
// @todo: How it can get the mozilla vesion?
}
// Now, parse product version ...
if (prodDesc != null) {
int sI = productAddition.indexOf(prodDesc) + prodDesc.length() + 1;
int eI = productAddition.indexOf(' ', sI);
if (eI == -1) {
eI = productAddition.length();
}
final String productVersion = productAddition.substring(sI, eI);
parseVersion(productVersion);
}
} else if (userAgentHeader.contains("Opera")) {
// Opera:
// Samples: Opera/9.0 (Windows NT 5.1; U; en)
// Opera/8.5 (Macintosh; PPC Mac OS X; U; en)
// Mozilla/5.0 (Macintosh; PPC Mac OS X; U; en) Opera 8.5
// Mozilla/4.0 (compatible; MSIE 6.0; Mac_PowerPC Mac OS X; en) Opera 8.5
// Opera/9.21 (Windows NT 5.1; U; en)
this.product = Product.OPERA;
String productVersion;
if (application.startsWith("Opera")) {
productVersion = application.substring(application.indexOf('/') + 1, application.length());
} else {
productVersion = productAddition.substring(application.lastIndexOf(' ') + 1, application.length());
}
parseVersion(productVersion);
} else if (userAgentHeader.contains("4.7")) {
this.product = Product.NETSCAPE;
} else if (userAgentHeader.contains("Lynx")) {
this.product = Product.LYNX;
} else {
// It's a robot ..
for (String botAgent : botAgents) {
if (userAgentHeader.contains(botAgent)) {
// set a key in the session, so the next time we don't have to manually
// detect the robot again
this.product = Product.ROBOT;
break;
}
}
logger.info("UserAgent could not be detected: '" + userAgentHeader + "'");
}
} catch (Throwable e) {
logger.error("Could not detect the browser based on the user agent: '" + userAgentHeader + "'");
// Mark as an unsupported browser...
this.product = Product.ROBOT;
}
}
private OS parseOS(String details) {
OS result;
if (details.contains("Windows"))
result = OS.WINDOWS;
else if (details.contains("Mac") || details.contains("Macintosh"))
result = OS.MAC;
else if (details.contains("X11"))
result = OS.LINUX;
else
result = OS.KNOWN;
return result;
}
public static UserAgent create(final HttpServletRequest request) {
final String userAgent = request.getHeader(USER_AGENT_HEADER);
return new UserAgent(userAgent);
}
public static UserAgent create(final String userAgent) {
return new UserAgent(userAgent);
}
private void parseVersion(final String version) {
final int index = version.indexOf('.');
final String vm = version.substring(0, index);
final String vv = version.substring(index + 1, version.length());
this.versionMajor = Integer.parseInt(vm);
char c = vv.charAt(0);
this.versionVariation = Integer.valueOf(String.valueOf(c));
}
/**
* All known robot user-agent headers (list can be found
* <a href="http://www.robotstxt.org/wc/activel">here</a>).
* <p/>
* <p>NOTE: To avoid bad detection:</p>
* <p/>
* <ul>
* <li>Robots with ID of 2 letters only were removed</li>
* <li>Robot called "webs" were removed</li>
* <li>directhit was changed in direct_hit (its real id)</li>
* </ul>
*/
private static final String[] botAgents = {
"acme.spider", "ahoythehomepagefinder", "alkaline", "appie", "arachnophilia",
"architext", "aretha", "ariadne", "aspider", "atn.txt", "atomz", "auresys",
"backrub", "bigbrother", "bjaaland", "blackwidow", "blindekuh", "bloodhound",
"brightnet", "bspider", "cactvschemistryspider", "calif", "cassandra",
"cgireader", "checkbot", "churl", "cmc", "collective", "combine", "conceptbot",
"core", "cshkust", "cusco", "cyberspyder", "deweb", "dienstspider", "diibot",
"direct_hit", "dnabot", "download_express", "dragonbot", "dwcp", "ebiness",
"eit", "emacs", "emcspider", "esther", "evliyacelebi", "fdse", "felix",
"ferret", "fetchrover", "fido", "finnish", "fireball", "fish", "fouineur",
"francoroute", "freecrawl", "funnelweb", "gazz", "gcreep", "getbot", "geturl",
"golem", "googlebot", "grapnel", "griffon", "gromit", "gulliver", "hambot",
"harvest", "havindex", "hometown", "wired-digital", "htdig", "htmlgobble",
"hyperdecontextualizer", "ibm", "iconoclast", "ilse", "imagelock", "incywincy",
"informant", "infoseek", "infoseeksidewinder", "infospider", "inspectorwww",
"intelliagent", "iron33", "israelisearch", "javabee", "jcrawler", "jeeves",
"jobot", "joebot", "jubii", "jumpstation", "katipo", "kdd", "kilroy",
"ko_yappo_robot", "labelgrabber.txt", "larbin", "legs", "linkscan",
"linkwalker", "lockon", "logo_gif", "lycos", "macworm", "magpie", "mediafox",
"merzscope", "meshexplorer", "mindcrawler", "moget", "momspider", "monster",
"motor", "muscatferret", "mwdsearch", "myweb", "netcarta", "netmechanic",
"netscoop", "newscan-online", "nhse", "nomad", "northstar", "nzexplorer",
"occam", "octopus", "orb_search", "packrat", "pageboy", "parasite", "patric",
"perignator", "perlcrawler", "phantom", "piltdownman", "pioneer", "pitkow",
"pjspider", "pka", "plumtreewebaccessor", "poppi", "portalb", "puu", "python",
"raven", "rbse", "resumerobot", "rhcs", "roadrunner", "robbie", "robi",
"roverbot", "safetynetrobot", "scooter", "search_au", "searchprocess",
"senrigan", "sgscout", "shaggy", "shaihulud", "sift", "simbot", "site-valet",
"sitegrabber", "sitetech", "slurp", "smartspider", "snooper", "solbot",
"spanner", "speedy", "spider_monkey", "spiderbot", "spiderman", "spry",
"ssearcher", "suke", "sven", "tach_bw", "tarantula", "tarspider", "tcl",
"techbot", "templeton", "titin", "titan", "tkwww", "tlspider", "ucsd",
"udmsearch", "urlck", "valkyrie", "victoria", "visionsearch", "voyager",
"vwbot", "w3index", "w3m2", "wanderer", "webbandit", "webcatcher", "webcopy",
"webfetcher", "webfoot", "weblayers", "weblinker", "webmirror", "webmoose",
"webquest", "webreader", "webreaper", "websnarf", "webspider", "webvac",
"webwalk", "webwalker", "webwatch", "wget", "whowhere", "wmir", "wolp",
"wombat", "worm", "wwwc", "wz101", "xget", "nederland.zoek"
};
public boolean isBrowserSupported() {
// Is it a supported browser ?.
final UserAgent.Product product = this.getProduct();
boolean result = product == UserAgent.Product.FIREFOX && this.isVersionGreatedOrEqualThan(10, 0);
result = result || product == UserAgent.Product.EXPLORER && this.isVersionGreatedOrEqualThan(7, 0) && this.getOs() == UserAgent.OS.WINDOWS;
result = result || product == UserAgent.Product.OPERA && this.isVersionGreatedOrEqualThan(11, 0);
result = result || product == UserAgent.Product.CHROME && this.isVersionGreatedOrEqualThan(18, 0);
result = result || product == UserAgent.Product.SAFARI && this.isVersionGreatedOrEqualThan(5, 0);
result = result || product == Product.WEB_CRAWLER;
return result;
}
public boolean needsGCF() {
final UserAgent.Product product = this.getProduct();
return product == UserAgent.Product.EXPLORER && this.isVersionLessThan(9) && this.getOs() == UserAgent.OS.WINDOWS && !this.hasGCFInstalled;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright [2011] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.filter;
import com.sun.istack.internal.NotNull;
import com.wisemapping.util.*;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
public class WiseUserAgent implements Serializable {
public static final String USER_AGENT_HEADER = "User-Agent";
private UserAgent userAgent;
private String header;
private WiseUserAgent(@NotNull final String header) {
this.header = header;
this.userAgent = new UserAgent(header);
}
public static WiseUserAgent create(@NotNull final HttpServletRequest request) {
return new WiseUserAgent(request.getHeader(USER_AGENT_HEADER));
}
public boolean isBrowserSupported() {
final Browser browser = userAgent.getBrowser();
final Version version = userAgent.getBrowserVersion();
final OperatingSystem os = userAgent.getOperatingSystem();
boolean result = browser == Browser.FIREFOX && Integer.parseInt(version.getMajorVersion()) >= 10;
result = result || browser == Browser.IE8 || browser == Browser.IE9;
result = result || browser == Browser.IE && Integer.parseInt(version.getMajorVersion()) >= 8;
result = result || browser == Browser.OPERA && Integer.parseInt(version.getMajorVersion()) >= 11;
result = result || browser == Browser.CHROME && Integer.parseInt(version.getMajorVersion()) >= 18;
result = result || browser == Browser.SAFARI5;
result = result || browser == Browser.MOBILE_SAFARI && Integer.parseInt(version.getMajorVersion()) >= 5;
result = result || os.isMobileDevice() && (os == OperatingSystem.ANDROID || os == OperatingSystem.iOS4_IPHONE);
result = result || browser.getBrowserType() == BrowserType.ROBOT;
return result;
}
public boolean needsGCF() {
final Browser browser = userAgent.getBrowser();
final Version version = userAgent.getBrowserVersion();
final OperatingSystem os = userAgent.getOperatingSystem();
return browser == Browser.IE && Integer.parseInt(version.getMajorVersion()) >= 8 && os == OperatingSystem.WINDOWS && header.contains("chromeframe");
}
public static WiseUserAgent create(@NotNull final String userAgent) {
return new WiseUserAgent(userAgent);
}
}

View File

@ -18,9 +18,8 @@
package com.wisemapping.mail; package com.wisemapping.mail;
import com.wisemapping.filter.UserAgent; import com.wisemapping.filter.WiseUserAgent;
import com.wisemapping.model.Collaboration; import com.wisemapping.model.Collaboration;
import com.wisemapping.model.CollaborationRole;
import com.wisemapping.model.Mindmap; import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User; import com.wisemapping.model.User;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -176,7 +175,7 @@ final public class NotificationService {
final String userEmail = user != null ? user.getEmail() : "'anonymous'"; final String userEmail = user != null ? user.getEmail() : "'anonymous'";
model.put("email", userEmail); model.put("email", userEmail);
model.put("userAgent", request.getHeader(UserAgent.USER_AGENT_HEADER)); model.put("userAgent", request.getHeader(WiseUserAgent.USER_AGENT_HEADER));
model.put("server", request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()); model.put("server", request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort());
model.put("requestURI", request.getRequestURI()); model.put("requestURI", request.getRequestURI());
model.put("method", request.getMethod()); model.put("method", request.getMethod());

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2008, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Enum constants for internet applications like web-application and rich
* internet application.
*
* @author harald
*
*/
public enum Application {
HOTMAIL(Manufacturer.MICROSOFT, 1, "Windows Live Hotmail",
new String[] { "mail.live.com", "hotmail.msn" }, ApplicationType.WEBMAIL),
GMAIL( Manufacturer.GOOGLE, 5, "Gmail",
new String[] { "mail.google.com" }, ApplicationType.WEBMAIL),
YAHOO_MAIL( Manufacturer.YAHOO, 10, "Yahoo Mail",
new String[] { "mail.yahoo.com" }, ApplicationType.WEBMAIL),
COMPUSERVE( Manufacturer.COMPUSERVE, 20, "Compuserve",
new String[] { "csmail.compuserve.com" }, ApplicationType.WEBMAIL),
AOL_WEBMAIL( Manufacturer.AOL, 30, "AOL webmail",
new String[] { "webmail.aol.com" }, ApplicationType.WEBMAIL),
/**
* MobileMe webmail client by Apple. Previously known as .mac.
*/
MOBILEME( Manufacturer.APPLE, 40, "MobileMe",
new String[] { "www.me.com" }, ApplicationType.WEBMAIL),
/**
* Mail.com
* Mail.com provides consumers with web-based e-mail services
*/
MAIL_COM( Manufacturer.MMC, 50, "Mail.com",
new String[] { ".mail.com" }, ApplicationType.WEBMAIL),
/**
* Popular open source webmail client. Often installed by providers or privately.
*/
HORDE( Manufacturer.OTHER, 50, "horde",
new String[] { "horde" }, ApplicationType.WEBMAIL),
OTHER_WEBMAIL(Manufacturer.OTHER, 60, "Other webmail client",
new String[] { "webmail", "webemail" }, ApplicationType.WEBMAIL),
UNKNOWN(Manufacturer.OTHER, 0, "Unknown",
new String[0], ApplicationType.UNKNOWN);
private final short id;
private final String name;
private final String[] aliases;
private final ApplicationType applicationType;
private final Manufacturer manufacturer;
private Application(Manufacturer manufacturer, int versionId, String name,
String[] aliases, ApplicationType applicationType) {
this.id = (short) ((manufacturer.getId() << 8) + (byte) versionId);
this.name = name;
this.aliases = aliases;
this.applicationType = applicationType;
this.manufacturer = manufacturer;
}
public short getId() {
return id;
}
public String getName() {
return name;
}
/**
* @return the applicationType
*/
public ApplicationType getApplicationType() {
return applicationType;
}
/**
* @return the manufacturer
*/
public Manufacturer getManufacturer() {
return manufacturer;
}
/*
* Checks if the given referrer string matches to the application. Only
* checks for one specific application.
*/
public boolean isInReferrerString(String referrerString) {
for (String alias : aliases) {
if (referrerString.toLowerCase().indexOf(alias.toLowerCase()) != -1)
return true;
}
return false;
}
/*
* Iterates over all Application to compare the signature with the referrer
* string. If no match can be found Application.UNKNOWN will be returned.
*/
public static Application parseReferrerString(String referrerString) {
// skip the empty and "-" referrer
if (referrerString != null && referrerString.length() > 1) {
for (Application applicationInList : Application.values()) {
if (applicationInList.isInReferrerString(referrerString))
return applicationInList;
}
}
return Application.UNKNOWN;
}
/**
* Returns the enum constant of this type with the specified id. Throws
* IllegalArgumentException if the value does not exist.
*
* @param id
* @return
*/
public static Application valueOf(short id) {
for (Application application : Application.values()) {
if (application.getId() == id)
return application;
}
// same behavior as standard valueOf(string) method
throw new IllegalArgumentException("No enum const for id " + id);
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2008, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Enum constants classifying the different types of applications which are common in referrer strings
* @author harald
*
*/
public enum ApplicationType {
/**
* Webmail service like Windows Live Hotmail and Gmail.
*/
WEBMAIL("Webmail client"),
UNKNOWN("unknown");
private String name;
private ApplicationType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,352 @@
/*
* Copyright (c) 2011, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Enum constants for most common browsers, including e-mail clients and bots.
* @author harald
*
*/
public enum Browser {
OPERA( Manufacturer.OPERA, null, 1, "Opera", new String[] { "Opera" }, null, BrowserType.WEB_BROWSER, RenderingEngine.PRESTO, "Opera\\/(([\\d]+)\\.([\\w]+))"), // before MSIE
OPERA_MINI( Manufacturer.OPERA, Browser.OPERA, 20, "Opera Mini", new String[] { "Opera Mini"}, null, BrowserType.MOBILE_BROWSER, RenderingEngine.PRESTO, null), // Opera for mobile devices
/**
* For some strange reason Opera uses 9.80 in the user-agent string.
*/
OPERA10( Manufacturer.OPERA, Browser.OPERA, 10, "Opera 10", new String[] { "Opera/9.8" }, null, BrowserType.WEB_BROWSER, RenderingEngine.PRESTO, "Version\\/(([\\d]+)\\.([\\w]+))"),
OPERA9( Manufacturer.OPERA, Browser.OPERA, 5, "Opera 9", new String[] { "Opera/9" }, null, BrowserType.WEB_BROWSER, RenderingEngine.PRESTO, null),
KONQUEROR( Manufacturer.OTHER, null, 1, "Konqueror", new String[] { "Konqueror"}, null, BrowserType.WEB_BROWSER, RenderingEngine.KHTML, "Konqueror\\/(([0-9]+)\\.?([\\w]+)?(-[\\w]+)?)" ),
/**
* Outlook email client
*/
OUTLOOK( Manufacturer.MICROSOFT, null, 100, "Outlook", new String[] {"MSOffice"}, null, BrowserType.EMAIL_CLIENT, RenderingEngine.WORD, "MSOffice (([0-9]+))"), // before IE7
/**
* Microsoft Outlook 2007 identifies itself as MSIE7 but uses the html rendering engine of Word 2007.
* Example user agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 1.1.4322; MSOffice 12)
*/
OUTLOOK2007( Manufacturer.MICROSOFT, Browser.OUTLOOK, 107, "Outlook 2007", new String[] {"MSOffice 12"}, null, BrowserType.EMAIL_CLIENT, RenderingEngine.WORD, null), // before IE7
/**
* Outlook 2010 is still using the rendering engine of Word. http://www.fixoutlook.org
*/
OUTLOOK2010( Manufacturer.MICROSOFT, Browser.OUTLOOK, 108, "Outlook 2010", new String[] {"MSOffice 14"}, null, BrowserType.EMAIL_CLIENT, RenderingEngine.WORD, null), // before IE7
/**
* Family of Internet Explorer browsers
*/
IE( Manufacturer.MICROSOFT, null, 1, "Internet Explorer", new String[] { "MSIE"}, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, "MSIE (([\\d]+)\\.([\\w]+))" ), // before Mozilla
/**
* Since version 7 Outlook Express is identifying itself. By detecting Outlook Express we can not
* identify the Internet Explorer version which is probably used for the rendering.
* Obviously this product is now called Windows Live Mail Desktop or just Windows Live Mail.
*/
OUTLOOK_EXPRESS7( Manufacturer.MICROSOFT, Browser.IE, 110, "Windows Live Mail", new String[] {"Outlook-Express/7.0"}, null, BrowserType.EMAIL_CLIENT, RenderingEngine.TRIDENT, null), // before IE7, previously known as Outlook Express. First released in 2006, offered with different name later
/**
* Since 2007 the mobile edition of Internet Explorer identifies itself as IEMobile in the user-agent.
* If previous versions have to be detected, use the operating system information as well.
*/
IEMOBILE7( Manufacturer.MICROSOFT, Browser.IE, 121, "IE Mobile 7", new String[] { "IEMobile 7" }, null, BrowserType.MOBILE_BROWSER, RenderingEngine.TRIDENT, null), // before MSIE strings
IEMOBILE6( Manufacturer.MICROSOFT, Browser.IE, 120, "IE Mobile 6", new String[] { "IEMobile 6" }, null, BrowserType.MOBILE_BROWSER, RenderingEngine.TRIDENT, null), // before MSIE
IE9( Manufacturer.MICROSOFT, Browser.IE, 90, "Internet Explorer 9", new String[] { "MSIE 9" }, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, null ), // before MSIE
IE8( Manufacturer.MICROSOFT, Browser.IE, 80, "Internet Explorer 8", new String[] { "MSIE 8" }, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, null ), // before MSIE
IE7( Manufacturer.MICROSOFT, Browser.IE, 70, "Internet Explorer 7", new String[] { "MSIE 7" }, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, null), // before MSIE
IE6( Manufacturer.MICROSOFT, Browser.IE, 60, "Internet Explorer 6", new String[] { "MSIE 6" }, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, null ), // before MSIE
IE5_5( Manufacturer.MICROSOFT, Browser.IE, 55, "Internet Explorer 5.5", new String[] { "MSIE 5.5" }, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, null), // before MSIE
IE5( Manufacturer.MICROSOFT, Browser.IE, 50, "Internet Explorer 5", new String[] { "MSIE 5" }, null, BrowserType.WEB_BROWSER, RenderingEngine.TRIDENT, null ), // before MSIE
/**
* Google Chrome browser
*/
CHROME( Manufacturer.GOOGLE, null, 1, "Chrome", new String[] { "Chrome" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, "Chrome\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?(\\.[\\w]+)?)" ), // before Mozilla
CHROME10( Manufacturer.GOOGLE, Browser.CHROME, 15, "Chrome 10", new String[] { "Chrome/10" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, null ), // before Mozilla
CHROME9( Manufacturer.GOOGLE, Browser.CHROME, 10, "Chrome 9", new String[] { "Chrome/9" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, null ), // before Mozilla
CHROME8( Manufacturer.GOOGLE, Browser.CHROME, 5, "Chrome 8", new String[] { "Chrome/8" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, null ), // before Mozilla
OMNIWEB( Manufacturer.OTHER, null, 2, "Omniweb", new String[] { "OmniWeb" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, null), //
SAFARI( Manufacturer.APPLE, null, 1, "Safari", new String[] { "Safari" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, "Version\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?)" ), // before AppleWebKit
SAFARI5( Manufacturer.APPLE, Browser.SAFARI, 3, "Safari 5", new String[] { "Version/5" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, null ), // before AppleWebKit
MOBILE_SAFARI( Manufacturer.APPLE, Browser.SAFARI, 2, "Mobile Safari", new String[] { "Mobile Safari","Mobile/" }, null, BrowserType.MOBILE_BROWSER, RenderingEngine.WEBKIT, null ), // before Safari
SAFARI4( Manufacturer.APPLE, Browser.SAFARI, 4, "Safari 4", new String[] { "Version/4" }, null, BrowserType.WEB_BROWSER, RenderingEngine.WEBKIT, null ), // before AppleWebKit
APPLE_MAIL( Manufacturer.APPLE, null, 50, "Apple Mail", new String[] { "AppleWebKit" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.WEBKIT, null), // Microsoft Entrourage/Outlook 2010 also only identifies itself as AppleWebKit
LOTUS_NOTES( Manufacturer.OTHER, null, 3, "Lotus Notes", new String[] { "Lotus-Notes" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.OTHER, "Lotus-Notes\\/(([\\d]+)\\.([\\w]+))"), // before Mozilla
/*
* Thunderbird email client, based on the same Gecko engine Firefox is using.
*/
THUNDERBIRD( Manufacturer.MOZILLA, null, 110, "Thunderbird", new String[] { "Thunderbird" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.GECKO, "Thunderbird\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?(\\.[\\w]+)?)" ), // using Gecko Engine
THUNDERBIRD3( Manufacturer.MOZILLA, Browser.THUNDERBIRD, 130, "Thunderbird 3", new String[] { "Thunderbird/3" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.GECKO, null ), // using Gecko Engine
THUNDERBIRD2( Manufacturer.MOZILLA, Browser.THUNDERBIRD, 120, "Thunderbird 2", new String[] { "Thunderbird/2" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.GECKO, null ), // using Gecko Engine
CAMINO( Manufacturer.OTHER, null, 5, "Camino", new String[] { "Camino" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, "Camino\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?)" ), // using Gecko Engine
CAMINO2( Manufacturer.OTHER, Browser.CAMINO, 17, "Camino 2", new String[] { "Camino/2" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, null ), // using Gecko Engine
FLOCK( Manufacturer.OTHER, null, 4, "Flock", new String[]{"Flock"}, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, "Flock\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?)"),
FIREFOX( Manufacturer.MOZILLA, null, 10, "Firefox", new String[] { "Firefox" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, "Firefox\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?(\\.[\\w]+)?)"), // using Gecko Engine
FIREFOX3MOBILE( Manufacturer.MOZILLA, Browser.FIREFOX, 31, "Firefox 3 Mobile", new String[] { "Firefox/3.5 Maemo" }, null, BrowserType.MOBILE_BROWSER, RenderingEngine.GECKO, null ), // using Gecko Engine
FIREFOX4( Manufacturer.MOZILLA, Browser.FIREFOX, 40, "Firefox 4", new String[] { "Firefox/4" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, null ), // using Gecko Engine
FIREFOX3( Manufacturer.MOZILLA, Browser.FIREFOX, 30, "Firefox 3", new String[] { "Firefox/3" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, null ), // using Gecko Engine
FIREFOX2( Manufacturer.MOZILLA, Browser.FIREFOX, 20, "Firefox 2", new String[] { "Firefox/2" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, null ), // using Gecko Engine
FIREFOX1_5( Manufacturer.MOZILLA, Browser.FIREFOX, 15, "Firefox 1.5", new String[] { "Firefox/1.5" }, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, null ), // using Gecko Engine
SEAMONKEY( Manufacturer.OTHER, null, 15, "SeaMonkey", new String[]{"SeaMonkey"}, null, BrowserType.WEB_BROWSER, RenderingEngine.GECKO, "SeaMonkey\\/(([0-9]+)\\.?([\\w]+)?(\\.[\\w]+)?)"), // using Gecko Engine
BOT( Manufacturer.OTHER, null,12, "Robot/Spider", new String[]{"Mediapartners-Google","Googlebot","bot", "spider", "crawler", "Feedfetcher", "Slurp", "Twiceler", "Nutch", "BecomeBot"}, null, BrowserType.ROBOT, RenderingEngine.OTHER, null),
MOZILLA( Manufacturer.MOZILLA, null, 1, "Mozilla", new String[] { "Mozilla", "Moozilla" }, null, BrowserType.WEB_BROWSER, RenderingEngine.OTHER, null), // rest of the mozilla browsers
CFNETWORK( Manufacturer.OTHER, null, 6, "CFNetwork", new String[] { "CFNetwork" }, null, BrowserType.UNKNOWN, RenderingEngine.OTHER, null ), // Mac OS X cocoa library
EUDORA( Manufacturer.OTHER, null, 7, "Eudora", new String[] { "Eudora", "EUDORA" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.OTHER, null ), // email client by Qualcomm
POCOMAIL( Manufacturer.OTHER, null, 8, "PocoMail", new String[] { "PocoMail" }, null, BrowserType.EMAIL_CLIENT, RenderingEngine.OTHER, null ),
THEBAT( Manufacturer.OTHER, null, 9, "The Bat!", new String[]{"The Bat"}, null, BrowserType.EMAIL_CLIENT, RenderingEngine.OTHER, null), // Email Client
NETFRONT( Manufacturer.OTHER, null, 10, "NetFront", new String[]{"NetFront"}, null, BrowserType.MOBILE_BROWSER, RenderingEngine.OTHER, null), // mobile device browser
EVOLUTION( Manufacturer.OTHER, null, 11, "Evolution", new String[]{"CamelHttpStream"}, null, BrowserType.EMAIL_CLIENT, RenderingEngine.OTHER, null), // http://www.go-evolution.org/Camel.Stream
LYNX( Manufacturer.OTHER, null, 13, "Lynx", new String[]{"Lynx"}, null, BrowserType.TEXT_BROWSER, RenderingEngine.OTHER, "Lynx\\/(([0-9]+)\\.([\\d]+)\\.?([\\w-+]+)?\\.?([\\w-+]+)?)"),
DOWNLOAD( Manufacturer.OTHER, null, 16, "Downloading Tool", new String[]{"cURL","wget"}, null, BrowserType.TEXT_BROWSER, RenderingEngine.OTHER, null),
UNKNOWN( Manufacturer.OTHER, null, 14, "Unknown", new String[0], null, BrowserType.UNKNOWN, RenderingEngine.OTHER, null );
private final short id;
private final String name;
private final String[] aliases;
private final String[] excludeList; // don't match when these values are in the agent-string
private final BrowserType browserType;
private final Manufacturer manufacturer;
private final RenderingEngine renderingEngine;
private final Browser parent;
private List<Browser> children;
private Pattern versionRegEx;
private Browser(Manufacturer manufacturer, Browser parent, int versionId, String name, String[] aliases, String[] exclude, BrowserType browserType, RenderingEngine renderingEngine, String versionRegexString) {
this.id = (short) ( ( manufacturer.getId() << 8) + (byte) versionId);
this.name = name;
this.parent = parent;
this.children = new ArrayList<Browser>();
if (this.parent != null) {
this.parent.children.add(this);
}
this.aliases = aliases;
this.excludeList = exclude;
this.browserType = browserType;
this.manufacturer = manufacturer;
this.renderingEngine = renderingEngine;
if (versionRegexString != null) {
this.versionRegEx = Pattern.compile(versionRegexString);
}
}
public short getId() {
return id;
}
public String getName() {
return name;
}
private Pattern getVersionRegEx() {
if (this.versionRegEx == null) {
if (this.getGroup() != this)
return this.getGroup().getVersionRegEx();
else
return null;
}
return this.versionRegEx;
}
/**
* Detects the detailed version information of the browser. Depends on the userAgent to be available.
* Returns null if it can not detect the version information.
* @return Version
*/
public Version getVersion(String userAgentString) {
Pattern pattern = this.getVersionRegEx();
if (userAgentString != null && pattern != null) {
Matcher matcher = pattern.matcher(userAgentString);
if (matcher.find()) {
String fullVersionString = matcher.group(1);
String majorVersion = matcher.group(2);
String minorVersion = "0";
if (matcher.groupCount() > 2) // usually but not always there is a minor version
minorVersion = matcher.group(3);
return new Version (fullVersionString,majorVersion,minorVersion);
}
}
return null;
}
/**
* @return the browserType
*/
public BrowserType getBrowserType() {
return browserType;
}
/**
* @return the manufacturer
*/
public Manufacturer getManufacturer() {
return manufacturer;
}
/**
* @return the rendering engine
*/
public RenderingEngine getRenderingEngine() {
return renderingEngine;
}
/**
* @return top level browser family
*/
public Browser getGroup() {
if (this.parent != null) {
return parent.getGroup();
}
return this;
}
/*
* Checks if the given user-agent string matches to the browser.
* Only checks for one specific browser.
*/
public boolean isInUserAgentString(String agentString)
{
for (String alias : aliases)
{
if (agentString.toLowerCase().indexOf(alias.toLowerCase()) != -1)
return true;
}
return false;
}
/**
* Checks if the given user-agent does not contain one of the tokens which should not match.
* In most cases there are no excluding tokens, so the impact should be small.
* @param agentString
* @return
*/
private boolean containsExcludeToken(String agentString)
{
if (excludeList != null) {
for (String exclude : excludeList) {
if (agentString.toLowerCase().indexOf(exclude.toLowerCase()) != -1)
return true;
}
}
return false;
}
private Browser checkUserAgent(String agentString) {
if (this.isInUserAgentString(agentString)) {
if (this.children.size() > 0) {
for (Browser childBrowser : this.children) {
Browser match = childBrowser.checkUserAgent(agentString);
if (match != null) {
return match;
}
}
}
// if children didn't match we continue checking the current to prevent false positives
if (!this.containsExcludeToken(agentString)) {
return this;
}
}
return null;
}
/**
* Iterates over all Browsers to compare the browser signature with
* the user agent string. If no match can be found Browser.UNKNOWN will
* be returned.
* @param agentString
* @return Browser
*/
public static Browser parseUserAgentString(String agentString)
{
for (Browser browser : Browser.values())
{
// only check top level objects
if (browser.parent == null) {
Browser match = browser.checkUserAgent(agentString);
if (match != null) {
return match; // either current operatingSystem or a child object
}
}
}
return Browser.UNKNOWN;
}
/**
* Returns the enum constant of this type with the specified id.
* Throws IllegalArgumentException if the value does not exist.
* @param id
* @return
*/
public static Browser valueOf(short id)
{
for (Browser browser : Browser.values())
{
if (browser.getId() == id)
return browser;
}
// same behavior as standard valueOf(string) method
throw new IllegalArgumentException(
"No enum const for id " + id);
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2008, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Enum constants classifying the different types of browsers which are common in user-agent strings
* @author harald
*
*/
public enum BrowserType {
/**
* Standard web-browser
*/
WEB_BROWSER("Browser"),
/**
* Special web-browser for mobile devices
*/
MOBILE_BROWSER("Browser (mobile)"),
/**
* Text only browser like the good old Lynx
*/
TEXT_BROWSER("Browser (text only)"),
/**
* Email client like Thunderbird
*/
EMAIL_CLIENT("Email Client"),
/**
* Search robot, spider, crawler,...
*/
ROBOT("Robot"),
/**
* Downloading tools
*/
TOOL("Downloading tool"),
UNKNOWN("unknown");
private String name;
private BrowserType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,71 @@
/* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Enum contact for the type of used device
* @author harald
*
*/
public enum DeviceType {
/**
* Standard desktop or laptop computer
*/
COMPUTER("Computer"),
/**
* Mobile phone or similar small mobile device
*/
MOBILE("Mobile"),
/**
* Small tablet type computer.
*/
TABLET("Tablet"),
/**
* Game console like the Wii or Playstation.
*/
GAME_CONSOLE("Game console"),
/**
* Digital media receiver like the Apple TV.
* No device detection implemented yet for this category. Please send provide user-agent strings if you have some.
*/
DMR("Digital media receiver"),
/**
* Other or unknow type of device.
*/
UNKNOWN("Unknown");
String name;
private DeviceType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,145 @@
/*
* Copyright (c) 2008, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Enum constants representing manufacturers of operating systems and client software.
* Manufacturer could be used for specific handling of browser requests.
* @author harald
*/
public enum Manufacturer {
/**
* Unknow or rare manufacturer
*/
OTHER(1, "Other"),
/**
* Microsoft Corporation
*/
MICROSOFT(2, "Microsoft Corporation"),
/**
* Apple Inc.
*/
APPLE(3, "Apple Inc."),
/**
* Sun Microsystems, Inc.
*/
SUN(4, "Sun Microsystems, Inc."),
/**
* Symbian Ltd.
*/
SYMBIAN(5, "Symbian Ltd."),
/**
* Nokia Corporation
*/
NOKIA(6, "Nokia Corporation"),
/**
* Research In Motion Limited
*/
BLACKBERRY(7, "Research In Motion Limited"),
/**
* Palm, Inc.
*/
PALM(8, "Palm, Inc. "),
/**
* Sony Ericsson Mobile Communications AB
*/
SONY_ERICSSON(9, "Sony Ericsson Mobile Communications AB"),
/**
* Sony Computer Entertainment, Inc.
*/
SONY(10, "Sony Computer Entertainment, Inc."),
/**
* Nintendo
*/
NINTENDO(11, "Nintendo"),
/**
* Opera Software ASA
*/
OPERA(12, "Opera Software ASA"),
/**
* Mozilla Foundation
*/
MOZILLA(13, "Mozilla Foundation"),
/**
* Google Inc.
*/
GOOGLE(15, "Google Inc."),
/**
* CompuServe Interactive Services, Inc.
*/
COMPUSERVE(16, "CompuServe Interactive Services, Inc."),
/**
* Yahoo Inc.
*/
YAHOO(17, "Yahoo Inc."),
/**
* AOL LLC.
*/
AOL(18, "AOL LLC."),
/**
* Mail.com Media Corporation
*/
MMC(19, "Mail.com Media Corporation")
;
private final byte id;
private final String name;
private Manufacturer(int id, String name) {
this.id = (byte) id;
this.name = name;
}
/**
* @return the id
*/
public byte getId() {
return id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
}

View File

@ -0,0 +1,305 @@
/*
* Copyright (c) 2011, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* Enum constants for most common operating systems.
* @author harald
*/
public enum OperatingSystem {
// the order is important since the agent string is being compared with the aliases
/**
* Windows Mobile / Windows CE. Exact version unknown.
*/
WINDOWS( Manufacturer.MICROSOFT,null,1, "Windows", new String[] { "Windows" }, new String[] { "Palm" }, DeviceType.COMPUTER, null ), // catch the rest of older Windows systems (95, NT,...)
WINDOWS_7( Manufacturer.MICROSOFT,OperatingSystem.WINDOWS,21, "Windows 7", new String[] { "Windows NT 6.1" }, null, DeviceType.COMPUTER, null ), // before Win, yes, Windows 7 is called 6.1 LOL
WINDOWS_VISTA( Manufacturer.MICROSOFT,OperatingSystem.WINDOWS,20, "Windows Vista", new String[] { "Windows NT 6" }, null, DeviceType.COMPUTER, null ), // before Win
WINDOWS_2000( Manufacturer.MICROSOFT,OperatingSystem.WINDOWS,15, "Windows 2000", new String[] { "Windows NT 5.0" }, null, DeviceType.COMPUTER, null ), // before Win
WINDOWS_XP( Manufacturer.MICROSOFT,OperatingSystem.WINDOWS,10, "Windows XP", new String[] { "Windows NT 5" }, null, DeviceType.COMPUTER, null ), // before Win, 5.1 and 5.2 are basically XP systems
WINDOWS_MOBILE7(Manufacturer.MICROSOFT,OperatingSystem.WINDOWS, 51, "Windows Mobile 7", new String[] { "Windows Phone OS 7" }, null, DeviceType.MOBILE, null ), // before Win
WINDOWS_MOBILE( Manufacturer.MICROSOFT,OperatingSystem.WINDOWS, 50, "Windows Mobile", new String[] { "Windows CE" }, null, DeviceType.MOBILE, null ), // before Win
WINDOWS_98( Manufacturer.MICROSOFT,OperatingSystem.WINDOWS,5, "Windows 98", new String[] { "Windows 98","Win98" }, new String[] { "Palm" }, DeviceType.COMPUTER, null ), // before Win
ANDROID( Manufacturer.GOOGLE,null, 0, "Android", new String[] { "Android" }, null, DeviceType.MOBILE, null ),
ANDROID2( Manufacturer.GOOGLE,OperatingSystem.ANDROID, 2, "Android 2.x", new String[] { "Android 2" }, null, DeviceType.MOBILE, null ),
ANDROID2_TABLET(Manufacturer.GOOGLE,OperatingSystem.ANDROID2, 20, "Android 2.x Tablet", new String[] { "GT-P1000","SCH-I800" }, null, DeviceType.TABLET, null ),
ANDROID1( Manufacturer.GOOGLE,OperatingSystem.ANDROID, 1, "Android 1.x", new String[] { "Android 1" }, null, DeviceType.MOBILE, null ),
/**
* PalmOS, exact version unkown
*/
WEBOS( Manufacturer.PALM,null,11, "WebOS", new String[] { "webOS" }, null, DeviceType.MOBILE, null ),
PALM( Manufacturer.PALM,null,10, "PalmOS", new String[] { "Palm" }, null, DeviceType.MOBILE, null ),
/**
* iOS4, with the release of the iPhone 4, Apple renamed the OS to iOS.
*/
IOS(Manufacturer.APPLE,null, 2, "iOS", new String[] { "like Mac OS X" }, null, DeviceType.MOBILE, null ), // before MAC_OS_X_IPHONE for all older versions
iOS4_IPHONE(Manufacturer.APPLE,OperatingSystem.IOS, 41, "iOS 4 (iPhone)", new String[] { "iPhone OS 4" }, null, DeviceType.MOBILE, null ), // before MAC_OS_X_IPHONE for all older versions
MAC_OS_X_IPAD( Manufacturer.APPLE, OperatingSystem.IOS, 50, "Mac OS X (iPad)", new String[] { "iPad" }, null, DeviceType.TABLET, null ), // before Mac OS X
MAC_OS_X_IPHONE(Manufacturer.APPLE, OperatingSystem.IOS, 40, "Mac OS X (iPhone)", new String[] { "iPhone" }, null, DeviceType.MOBILE, null ), // before Mac OS X
MAC_OS_X_IPOD( Manufacturer.APPLE, OperatingSystem.IOS, 30, "Mac OS X (iPod)", new String[] { "iPod" }, null, DeviceType.MOBILE, null ), // before Mac OS X
MAC_OS_X( Manufacturer.APPLE,null, 10, "Mac OS X", new String[] { "Mac OS X" , "CFNetwork"}, null, DeviceType.COMPUTER, null ), // before Mac
/**
* Older Mac OS systems before Mac OS X
*/
MAC_OS( Manufacturer.APPLE,null, 1, "Mac OS", new String[] { "Mac" }, null, DeviceType.COMPUTER, null ), // older Mac OS systems
/**
* Linux based Maemo software platform by Nokia. Used in the N900 phone. http://maemo.nokia.com/
*/
MAEMO( Manufacturer.NOKIA,null, 2, "Maemo", new String[] { "Maemo" }, null, DeviceType.MOBILE, null ),
/**
* Various Linux based operating systems.
*/
LINUX( Manufacturer.OTHER,null, 2, "Linux", new String[] { "Linux" , "CamelHttpStream" }, null, DeviceType.COMPUTER, null ), // CamelHttpStream is being used by Evolution, an email client for Linux
/**
* Other Symbian OS versions
*/
SYMBIAN( Manufacturer.SYMBIAN,null, 1, "Symbian OS", new String[] { "Symbian", "Series60"}, null, DeviceType.MOBILE, null ),
/**
* Symbian OS 9.x versions. Being used by Nokia (N71, N73, N81, N82, N91, N92, N95, ...)
*/
SYMBIAN9( Manufacturer.SYMBIAN,OperatingSystem.SYMBIAN, 20, "Symbian OS 9.x", new String[] {"SymbianOS/9", "Series60/3"}, null, DeviceType.MOBILE, null ),
/**
* Symbian OS 8.x versions. Being used by Nokia (6630, 6680, 6681, 6682, N70, N72, N90).
*/
SYMBIAN8( Manufacturer.SYMBIAN,OperatingSystem.SYMBIAN, 15, "Symbian OS 8.x", new String[] { "SymbianOS/8", "Series60/2.6", "Series60/2.8"}, null, DeviceType.MOBILE, null ),
/**
* Symbian OS 7.x versions. Being used by Nokia (3230, 6260, 6600, 6620, 6670, 7610),
* Panasonic (X700, X800), Samsung (SGH-D720, SGH-D730) and Lenovo (P930).
*/
SYMBIAN7( Manufacturer.SYMBIAN,OperatingSystem.SYMBIAN, 10, "Symbian OS 7.x", new String[] { "SymbianOS/7"}, null, DeviceType.MOBILE, null ),
/**
* Symbian OS 6.x versions.
*/
SYMBIAN6( Manufacturer.SYMBIAN,OperatingSystem.SYMBIAN, 5, "Symbian OS 6.x", new String[] { "SymbianOS/6"}, null, DeviceType.MOBILE, null ),
/**
* Nokia's Series 40 operating system. Series 60 (S60) uses the Symbian OS.
*/
SERIES40 ( Manufacturer.NOKIA,null, 1, "Series 40", new String[] { "Nokia6300"}, null, DeviceType.MOBILE, null ),
/**
* Proprietary operating system used for many Sony Ericsson phones.
*/
SONY_ERICSSON ( Manufacturer.SONY_ERICSSON, null, 1, "Sony Ericsson", new String[] { "SonyEricsson"}, null, DeviceType.MOBILE, null ), // after symbian, some SE phones use symbian
SUN_OS( Manufacturer.SUN, null, 1, "SunOS", new String[] { "SunOS" } , null, DeviceType.COMPUTER, null ),
PSP( Manufacturer.SONY, null, 1, "Sony Playstation", new String[] { "Playstation" }, null, DeviceType.GAME_CONSOLE, null ),
/**
* Nintendo Wii game console.
*/
WII( Manufacturer.NINTENDO,null, 1, "Nintendo Wii", new String[] { "Wii" }, null, DeviceType.GAME_CONSOLE, null ),
/**
* BlackBerryOS. The BlackBerryOS exists in different version. How relevant those versions are, is not clear.
*/
BLACKBERRY( Manufacturer.BLACKBERRY,null, 1, "BlackBerryOS", new String[] { "BlackBerry" }, null, DeviceType.MOBILE, null ),
BLACKBERRY6( Manufacturer.BLACKBERRY,OperatingSystem.BLACKBERRY, 6, "BlackBerry 6", new String[] { "Version/6" }, null, DeviceType.MOBILE, null ),
UNKNOWN( Manufacturer.OTHER,null, 1, "Unknown", new String[0], null, DeviceType.UNKNOWN, null );
private final short id;
private final String name;
private final String[] aliases;
private final String[] excludeList; // don't match when these values are in the agent-string
private final Manufacturer manufacturer;
private final DeviceType deviceType;
private final OperatingSystem parent;
private List<OperatingSystem> children;
private Pattern versionRegEx;
private OperatingSystem(Manufacturer manufacturer, OperatingSystem parent, int versionId, String name, String[] aliases,
String[] exclude, DeviceType deviceType, String versionRegexString) {
this.manufacturer = manufacturer;
this.parent = parent;
this.children = new ArrayList<OperatingSystem>();
if (this.parent != null) {
this.parent.children.add(this);
}
// combine manufacturer and version id to one unique id.
this.id = (short) ( ( manufacturer.getId() << 8) + (byte) versionId);
this.name = name;
this.aliases = aliases;
this.excludeList = exclude;
this.deviceType = deviceType;
if (versionRegexString != null) {
this.versionRegEx = Pattern.compile(versionRegexString);
}
}
public short getId() {
return id;
}
public String getName() {
return name;
}
/*
* Shortcut to check of an operating system is a mobile device.
* Left in here for backwards compatibility.
*/
public boolean isMobileDevice() {
return deviceType.equals(DeviceType.MOBILE);
}
public DeviceType getDeviceType() {
return deviceType;
}
/*
* Gets the top level grouping operating system
*/
public OperatingSystem getGroup() {
if (this.parent != null) {
return parent.getGroup();
}
return this;
}
/**
* Returns the manufacturer of the operating system
* @return the manufacturer
*/
public Manufacturer getManufacturer() {
return manufacturer;
}
/**
* Checks if the given user-agent string matches to the operating system.
* Only checks for one specific operating system.
* @param agentString
* @return boolean
*/
public boolean isInUserAgentString(String agentString)
{
for (String alias : aliases)
{
if (agentString.toLowerCase().indexOf(alias.toLowerCase()) != -1)
return true;
}
return false;
}
/**
* Checks if the given user-agent does not contain one of the tokens which should not match.
* In most cases there are no excluding tokens, so the impact should be small.
* @param agentString
* @return
*/
private boolean containsExcludeToken(String agentString)
{
if (excludeList != null) {
for (String exclude : excludeList) {
if (agentString.toLowerCase().indexOf(exclude.toLowerCase()) != -1)
return true;
}
}
return false;
}
private OperatingSystem checkUserAgent(String agentString) {
if (this.isInUserAgentString(agentString)) {
if (this.children.size() > 0) {
for (OperatingSystem childOperatingSystem : this.children) {
OperatingSystem match = childOperatingSystem.checkUserAgent(agentString);
if (match != null) {
return match;
}
}
}
// if children didn't match we continue checking the current to prevent false positives
if (!this.containsExcludeToken(agentString)) {
return this;
}
}
return null;
}
/**
* Parses user agent string and returns the best match.
* Returns OperatingSystem.UNKNOWN if there is no match.
* @param agentString
* @return OperatingSystem
*/
public static OperatingSystem parseUserAgentString(String agentString)
{
for (OperatingSystem operatingSystem : OperatingSystem.values())
{
// only check top level objects
if (operatingSystem.parent == null) {
OperatingSystem match = operatingSystem.checkUserAgent(agentString);
if (match != null) {
return match; // either current operatingSystem or a child object
}
}
}
return OperatingSystem.UNKNOWN;
}
/**
* Returns the enum constant of this type with the specified id.
* Throws IllegalArgumentException if the value does not exist.
* @param id
* @return
*/
public static OperatingSystem valueOf(short id)
{
for (OperatingSystem operatingSystem : OperatingSystem.values())
{
if (operatingSystem.getId() == id)
return operatingSystem;
}
// same behavior as standard valueOf(string) method
throw new IllegalArgumentException(
"No enum const for id " + id);
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2011, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Enum constants classifying the different types of rendering engines which are being used by browsers.
* @author harald
*
*/
public enum RenderingEngine {
/**
* Trident is the the Microsoft layout engine, mainly used by Internet Explorer.
*/
TRIDENT("Trident"),
/**
* HTML parsing and rendering engine of Microsoft Office Word, used by some other products of the Office suite instead of Trident.
*/
WORD("Microsoft Office Word"),
/**
* Open source and cross platform layout engine, used by Firefox and many other browsers.
*/
GECKO("Gecko"),
/**
* Layout engine based on KHTML, used by Safari, Chrome and some other browsers.
*/
WEBKIT("WebKit"),
/**
* Proprietary layout engine by Opera Software ASA
*/
PRESTO("Presto"),
/**
* Original layout engine of the Mozilla browser and related products. Predecessor of Gecko.
*/
MOZILLA("Mozilla"),
/**
* Layout engine of the KDE project
*/
KHTML("KHTML"),
/**
* Other or unknown layout engine.
*/
OTHER("Other");
String name;
private RenderingEngine(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,220 @@
/*
* Copyright (c) 2008, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Container class for user-agent information with operating system and browser details.
* Can decode user-agent strings.
* <br><br>
* Resources:<br>
* <a href="http://www.useragentstring.com">User Agent String.Com</a><br>
* <a href="http://www.user-agents.org">List of User-Agents</a><br>
* <a href="http://www.zytrax.com/tech/web/browser_ids.htm">Browser ID (User-Agent) Strings</a><br>
* <a href="http://www.zytrax.com/tech/web/mobile_ids.html">Mobile Browser ID (User-Agent) Strings</a><br>
* <a href="http://www.joergkrusesweb.de/internet/browser/user-agent.html">Browser-Kennungen</a><br>
* <a href="http://deviceatlas.com/devices">Device Atlas - Mobile Device Intelligence</a><br>
* <a href="http://mobileopera.com/reference/ua">Mobile Opera user-agent strings</a><br>
* <a href="http://en.wikipedia.org/wiki/S60_platform">S60 platform</a><br>
* <a href="http://msdn.microsoft.com/en-us/library/ms537503.aspx">Understanding User-Agent Strings</a><br>
* <a href="http://developer.sonyericsson.com/site/global/docstools/browsing/p_browsing.jsp">Sony Ericsson Web Docs & Tools</a><br>
* <a href="http://developer.apple.com/internet/safari/faq.html#anchor2">What is the Safari user-agent string</a><br>
* <a href="http://www.pgts.com.au/pgtsj/pgtsj0208c.html">List of User Agent Strings</a><br>
* <a href="http://blogs.msdn.com/iemobile/archive/2006/08/03/Detecting_IE_Mobile.aspx">Detecting Internet Explorer Mobile's User-Agent on the server</a>
*/
/**
* @author harald
*
*/
public class UserAgent
{
private OperatingSystem operatingSystem = OperatingSystem.UNKNOWN;
private Browser browser = Browser.UNKNOWN;
private int id;
private String userAgentString;
public UserAgent(OperatingSystem operatingSystem, Browser browser)
{
this.operatingSystem = operatingSystem;
this.browser = browser;
this.id = (( operatingSystem.getId() << 16) + browser.getId());
}
public UserAgent(String userAgentString)
{
Browser browser = Browser.parseUserAgentString(userAgentString);
OperatingSystem operatingSystem = OperatingSystem.UNKNOWN;
// BOTs don't have an interesting OS for us
if (browser != Browser.BOT)
operatingSystem = OperatingSystem.parseUserAgentString(userAgentString);
this.operatingSystem = operatingSystem;
this.browser = browser;
this.id = (( operatingSystem.getId() << 16) + browser.getId());
this.userAgentString = userAgentString;
}
/**
* @param userAgentString
* @return UserAgent
*/
public static UserAgent parseUserAgentString(String userAgentString) {
return new UserAgent(userAgentString);
}
/**
* Detects the detailed version information of the browser. Depends on the userAgent to be available.
* Use it only after using UserAgent(String) or UserAgent.parseUserAgent(String).
* Returns null if it can not detect the version information.
* @return Version
*/
public Version getBrowserVersion() {
return this.browser.getVersion(this.userAgentString);
}
/**
* @return the system
*/
public OperatingSystem getOperatingSystem() {
return operatingSystem;
}
/**
* @return the browser
*/
public Browser getBrowser() {
return browser;
}
/**
* Returns an unique integer value of the operating system & browser combination
* @return the id
*/
public int getId() {
return id;
}
/**
* Combined string representation of both enums
*/
public String toString() {
return this.operatingSystem.toString() + "-" + this.browser.toString();
}
/**
* Returns UserAgent based on specified unique id
* @param id
* @return
*/
public static UserAgent valueOf(int id)
{
OperatingSystem operatingSystem = OperatingSystem.valueOf((short) (id >> 16));
Browser browser = Browser.valueOf( (short) (id & 0x0FFFF));
return new UserAgent(operatingSystem,browser);
}
/**
* Returns UserAgent based on combined string representation
* @param name
* @return
*/
public static UserAgent valueOf(String name)
{
if (name == null)
throw new NullPointerException("Name is null");
String[] elements = name.split("-");
if (elements.length == 2)
{
OperatingSystem operatingSystem = OperatingSystem.valueOf(elements[0]);
Browser browser = Browser.valueOf(elements[1]);
return new UserAgent(operatingSystem,browser);
}
throw new IllegalArgumentException(
"Invalid string for userAgent " + name);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((browser == null) ? 0 : browser.hashCode());
result = prime * result + id;
result = prime * result
+ ((operatingSystem == null) ? 0 : operatingSystem.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final UserAgent other = (UserAgent) obj;
if (browser == null) {
if (other.browser != null)
return false;
} else if (!browser.equals(other.browser))
return false;
if (id != other.id)
return false;
if (operatingSystem == null) {
if (other.operatingSystem != null)
return false;
} else if (!operatingSystem.equals(other.operatingSystem))
return false;
return true;
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2011, Harald Walker (bitwalker.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of bitwalker nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.wisemapping.util;
/**
* Container for general version information.
* All version information is stored as String as sometimes version information includes alphabetical characters.
* @author harald
*/
public class Version {
String version;
String majorVersion;
String minorVersion;
public Version(String version, String majorVersion, String minorVersion) {
super();
this.version = version;
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
}
public String getVersion() {
return version;
}
public String getMajorVersion() {
return majorVersion;
}
public String getMinorVersion() {
return minorVersion;
}
@Override
public String toString() {
return version;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((majorVersion == null) ? 0 : majorVersion.hashCode());
result = prime * result
+ ((minorVersion == null) ? 0 : minorVersion.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Version other = (Version) obj;
if (majorVersion == null) {
if (other.majorVersion != null)
return false;
} else if (!majorVersion.equals(other.majorVersion))
return false;
if (minorVersion == null) {
if (other.minorVersion != null)
return false;
} else if (!minorVersion.equals(other.minorVersion))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
}

View File

@ -11,26 +11,45 @@
}); });
</script> </script>
<div class="row"> <div class="row-fluid">
<div class="span1"></div>
<div class="span5" style="margin-top: 20px"> <div class="span5" style="margin-top: 20px">
<h1><spring:message code="WELCOME_TO_WISEMAPPING"/></h1> <h1><spring:message code="WELCOME_TO_WISEMAPPING"/></h1>
<spring:message code="WELCOME_DETAILS"/> <spring:message code="WELCOME_DETAILS"/>
</div> </div>
<div class="span1"></div> <div class="span1">
<div id="login" class="fform span4">
<h1>
<spring:message code="SIGN_IN"/>
</h1>
<form action="<c:url value='/c/j_spring_security_check'/>" method="POST"> </div>
<fieldset> <div id="login" class="fform span6">
<label for="email"><spring:message code="EMAIL"/></label> <h1><spring:message code="SIGN_IN"/></h1>
<input type='email' tabindex="1" id="email" name='j_username' required="required"/>
<label for="password"><spring:message code="PASSWORD"/></label> <form action="<c:url value='/c/j_spring_security_check'/>" method="POST" class="form-horizontal">
<input type='password' tabindex="2" id="password" name='j_password' required="required"/> <div class="control-group">
<label class="control-label" for="email"><spring:message code="EMAIL"/></label>
<div class="controls">
<input type='email' tabindex="1" id="email" name='j_username' required="required" class="span12"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password"><spring:message code="PASSWORD"/></label>
<div class="controls">
<input type='password' tabindex="2" id="password" name='j_password' required="required"
class="span12"/>
</div>
</div>
<div class="control-group" style="text-align: right">
<label>
<button class="btn btn-primary" tabindex="4"><spring:message code="SIGN_IN"/></button>
<input type="checkbox" id="rememberme" name="_spring_security_remember_me"
tabindex="3"/> <spring:message code="REMEMBER_ME"/>
</label>
<div style="text-align: center">
<a href="<c:url value="/c/user/resetPassword"/>"><spring:message code="FORGOT_PASSWORD"/></a>
</div>
</div>
<div class="control-group">
<c:if test="${not empty param.login_error}"> <c:if test="${not empty param.login_error}">
<c:choose> <c:choose>
<c:when test="${param.login_error == 3}"> <c:when test="${param.login_error == 3}">
@ -41,17 +60,8 @@
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
</c:if> </c:if>
</div>
<div class="form-inline">
<button class="btn btn-primary" data-loading-text="<spring:message code="SIGN_ING"/>" tabindex="4">
<spring:message code="SIGN_IN"/></button>
&nbsp;&nbsp;&nbsp;
<input type="checkbox" id="rememberme" name="_spring_security_remember_me" tabindex="3"/>
<label for="rememberme"><spring:message code="REMEMBER_ME"/></label>
</div>
</fieldset>
</form> </form>
<a href="<c:url value="/c/user/resetPassword"/>"><spring:message code="FORGOT_PASSWORD"/></a>
</div> </div>
</div> </div>

View File

@ -0,0 +1,52 @@
package com.wisemapping.test.model;
import com.wisemapping.filter.WiseUserAgent;
import org.testng.Assert;
import org.testng.annotations.Test;
@Test
public class UserAgentTest {
@Test
public void validations() {
final WiseUserAgent firefox15 = WiseUserAgent.create("Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15");
Assert.assertEquals(firefox15.isBrowserSupported(), true);
final WiseUserAgent firefox9 = WiseUserAgent.create("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0a2) Gecko/20111101 Firefox/9.0a2");
Assert.assertEquals(firefox9.isBrowserSupported(), false);
final WiseUserAgent chrome18 = WiseUserAgent.create("Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/18.6.872.0 Safari/535.2 UNTRUSTED/1.0 3gpp-gba UNTRUSTED/1.0");
Assert.assertEquals(chrome18.isBrowserSupported(), true);
final WiseUserAgent chrome21 = WiseUserAgent.create("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1");
Assert.assertEquals(chrome21.isBrowserSupported(), true);
final WiseUserAgent ie10 = WiseUserAgent.create("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/4.0; InfoPath.2; SV1; .NET CLR 2.0.50727; WOW64)");
Assert.assertEquals(ie10.isBrowserSupported(), true);
final WiseUserAgent ie10_6 = WiseUserAgent.create("Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0");
Assert.assertEquals(ie10_6.isBrowserSupported(), true);
final WiseUserAgent ie9 = WiseUserAgent.create("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET CLR 1.1.4322; .NET4.0C; Tablet PC 2.0)");
Assert.assertEquals(ie9.isBrowserSupported(), true);
final WiseUserAgent safari = WiseUserAgent.create("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; da-dk) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1");
Assert.assertEquals(safari.isBrowserSupported(), true);
final WiseUserAgent safari6 = WiseUserAgent.create("Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25");
Assert.assertEquals(safari6.isBrowserSupported(), true);
final WiseUserAgent safariIpad = WiseUserAgent.create("Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25");
Assert.assertEquals(safariIpad.isBrowserSupported(), true);
final WiseUserAgent googlebot = WiseUserAgent.create("Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)");
Assert.assertEquals(googlebot.isBrowserSupported(), true);
final WiseUserAgent mediapartners = WiseUserAgent.create("Mediapartners-Google/2.1");
Assert.assertEquals(mediapartners.isBrowserSupported(), true);
}
}