001package org.apache.turbine.util; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.concurrent.ConcurrentHashMap; 023import java.util.concurrent.ConcurrentMap; 024 025import nl.basjes.parse.useragent.UserAgent; 026import nl.basjes.parse.useragent.UserAgentAnalyzer; 027 028/** 029 * This class parses the user agent string and provides getters for 030 * its parts. It uses YAUAA (https://yauaa.basjes.nl/) 031 * 032 * The initialization step for a full UserAgentAnalyzer 033 * (i.e. all fields) usually takes something in the range of 2-5 seconds. 034 * 035 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a> 036 * @author <a href="mailto:leon@clearink.com">Leon Atkisnon</a> 037 * @author <a href="mailto:mospaw@polk-county.com">Chris Mospaw</a> 038 * @author <a href="mailto:bgriffin@cddb.com">Benjamin Elijah Griffin</a> 039 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a> 040 */ 041public class BrowserDetector 042{ 043 /** The user agent string. */ 044 private String userAgentString = ""; 045 046 /** The user agent parser */ 047 private static UserAgentAnalyzer uaa = UserAgentAnalyzer 048 .newBuilder() 049 .withFields(UserAgent.AGENT_NAME, 050 UserAgent.AGENT_VERSION, 051 UserAgent.OPERATING_SYSTEM_NAME) 052 .hideMatcherLoadStats() 053 .build(); 054 055 /** The user agent cache. */ 056 private static volatile ConcurrentMap<String, UserAgent> userAgentCache = 057 new ConcurrentHashMap<>(); 058 059 /** The browser name specified in the user agent string. */ 060 private String browserName = ""; 061 062 /** 063 * The browser version specified in the user agent string. If we 064 * can't parse the version just assume an old browser. 065 */ 066 private float browserVersion = (float) 1.0; 067 068 /** 069 * The browser platform specified in the user agent string. 070 */ 071 private String browserPlatform = "unknown"; 072 073 /** 074 * Constructor used to initialize this class. 075 * 076 * @param userAgentString A String with the user agent field. 077 */ 078 public BrowserDetector(String userAgentString) 079 { 080 this.userAgentString = userAgentString; 081 UserAgent userAgent = getUserAgent(); 082 083 // Get the browser name and version. 084 browserName = userAgent.getValue(UserAgent.AGENT_NAME); 085 String version = userAgent.getValue(UserAgent.AGENT_VERSION); 086 browserVersion = toFloat(version); 087 088 // Try to figure out what platform. 089 browserPlatform = userAgent.getValue(UserAgent.OPERATING_SYSTEM_NAME); 090 } 091 092 /** 093 * Constructor used to initialize this class. 094 * 095 * @param data The Turbine RunData object. 096 */ 097 public BrowserDetector(RunData data) 098 { 099 this(data.getUserAgent()); 100 } 101 102 /** 103 * The browser name specified in the user agent string. 104 * 105 * @return A String with the browser name. 106 */ 107 public String getBrowserName() 108 { 109 return browserName; 110 } 111 112 /** 113 * The browser platform specified in the user agent string. 114 * 115 * @return A String with the browser platform. 116 */ 117 public String getBrowserPlatform() 118 { 119 return browserPlatform; 120 } 121 122 /** 123 * The browser version specified in the user agent string. 124 * 125 * @return A String with the browser version. 126 */ 127 public float getBrowserVersion() 128 { 129 return browserVersion; 130 } 131 132 /** 133 * The user agent string for this class. 134 * 135 * @return A String with the user agent. 136 */ 137 public String getUserAgentString() 138 { 139 return userAgentString; 140 } 141 142 /** 143 * The user agent for this class. 144 * 145 * @return A user agent. 146 */ 147 public UserAgent getUserAgent() 148 { 149 return parse(userAgentString); 150 } 151 152 /** 153 * Helper method to initialize this class. 154 * 155 * @param userAgentString the user agent string 156 */ 157 private static UserAgent parse(String userAgentString) 158 { 159 return userAgentCache.computeIfAbsent(userAgentString, uaa::parse); 160 } 161 162 /** 163 * Helper method to convert String to a float. 164 * 165 * @param s A String. 166 * @return The String converted to float. 167 */ 168 private static final float toFloat(String s) 169 { 170 return Float.parseFloat(s); 171 } 172}