001 package 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
022 /**
023 * This class parses the user agent string and sets javasciptOK and
024 * cssOK following the rules described below. If you want to check
025 * for specific browsers/versions then use this class to parse the
026 * user agent string and use the accessor methods in this class.
027 *
028 * JavaScriptOK means that the browser understands JavaScript on the
029 * same level the Navigator 3 does. Specifically, it can use named
030 * images. This allows easier rollovers. If a browser doesn't do
031 * this (Nav 2 or MSIE 3), then we just assume it can't do any
032 * JavaScript. Referencing images by load order is too hard to
033 * maintain.
034 *
035 * CSSOK is kind of sketchy in that Nav 4 and MSIE work differently,
036 * but they do seem to have most of the functionality. MSIE 4 for the
037 * Mac has buggy CSS support, so we let it do JavaScript, but no CSS.
038 *
039 * Ported from Leon's PHP code at
040 * http://www.working-dogs.com/freetrade by Frank.
041 *
042 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
043 * @author <a href="mailto:leon@clearink.com">Leon Atkisnon</a>
044 * @author <a href="mailto:mospaw@polk-county.com">Chris Mospaw</a>
045 * @author <a href="mailto:bgriffin@cddb.com">Benjamin Elijah Griffin</a>
046 * @version $Id: BrowserDetector.java 615328 2008-01-25 20:25:05Z tv $
047 */
048 public class BrowserDetector
049 {
050 public static final String MSIE = "MSIE";
051 public static final String OPERA = "Opera";
052 public static final String MOZILLA = "Mozilla";
053
054 public static final String WINDOWS = "Windows";
055 public static final String UNIX = "Unix";
056 public static final String MACINTOSH = "Macintosh";
057
058 /** The user agent string. */
059 private String userAgentString = "";
060
061 /** The browser name specified in the user agent string. */
062 private String browserName = "";
063
064 /**
065 * The browser version specified in the user agent string. If we
066 * can't parse the version just assume an old browser.
067 */
068 private float browserVersion = (float) 1.0;
069
070 /**
071 * The browser platform specified in the user agent string.
072 */
073 private String browserPlatform = "unknown";
074
075 /** Whether or not javascript works in this browser. */
076 private boolean javascriptOK = false;
077
078 /** Whether or not CSS works in this browser. */
079 private boolean cssOK = false;
080
081 /** Whether or not file upload works in this browser. */
082 private boolean fileUploadOK = false;
083
084 /**
085 * Constructor used to initialize this class.
086 *
087 * @param userAgentString A String with the user agent field.
088 */
089 public BrowserDetector(String userAgentString)
090 {
091 this.userAgentString = userAgentString;
092 parse();
093 }
094
095 /**
096 * Constructor used to initialize this class.
097 *
098 * @param data The Turbine RunData object.
099 */
100 public BrowserDetector(RunData data)
101 {
102 this.userAgentString = data.getUserAgent();
103 parse();
104 }
105
106 /**
107 * Whether or not CSS works in this browser.
108 *
109 * @return True if CSS works in this browser.
110 */
111 public boolean isCssOK()
112 {
113 return cssOK;
114 }
115
116 /**
117 * Whether or not file upload works in this browser.
118 *
119 * @return True if file upload works in this browser.
120 */
121 public boolean isFileUploadOK()
122 {
123 return fileUploadOK;
124 }
125
126 /**
127 * Whether or not Javascript works in this browser.
128 *
129 * @return True if Javascript works in this browser.
130 */
131 public boolean isJavascriptOK()
132 {
133 return javascriptOK;
134 }
135
136 /**
137 * The browser name specified in the user agent string.
138 *
139 * @return A String with the browser name.
140 */
141 public String getBrowserName()
142 {
143 return browserName;
144 }
145
146 /**
147 * The browser platform specified in the user agent string.
148 *
149 * @return A String with the browser platform.
150 */
151 public String getBrowserPlatform()
152 {
153 return browserPlatform;
154 }
155
156 /**
157 * The browser version specified in the user agent string.
158 *
159 * @return A String with the browser version.
160 */
161 public float getBrowserVersion()
162 {
163 return browserVersion;
164 }
165
166 /**
167 * The user agent string for this class.
168 *
169 * @return A String with the user agent.
170 */
171 public String getUserAgentString()
172 {
173 return userAgentString;
174 }
175
176 /**
177 * Helper method to initialize this class.
178 */
179 private void parse()
180 {
181 int versionStartIndex = userAgentString.indexOf("/");
182 int versionEndIndex = userAgentString.indexOf(" ");
183
184 // Get the browser name and version.
185 browserName = userAgentString.substring(0, versionStartIndex);
186 try
187 {
188 // Not all user agents will have a space in the reported
189 // string.
190 String agentSubstring = null;
191 if (versionEndIndex < 0)
192 {
193 agentSubstring
194 = userAgentString.substring(versionStartIndex + 1);
195 }
196 else
197 {
198 agentSubstring = userAgentString
199 .substring(versionStartIndex + 1, versionEndIndex);
200 }
201 browserVersion = toFloat(agentSubstring);
202 }
203 catch (NumberFormatException e)
204 {
205 // Just use the default value.
206 }
207
208 // MSIE lies about its name. Of course...
209 if (userAgentString.indexOf(MSIE) != -1)
210 {
211 // Ex: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)
212 versionStartIndex = (userAgentString.indexOf(MSIE)
213 + MSIE.length() + 1);
214 versionEndIndex = userAgentString.indexOf(";", versionStartIndex);
215
216 browserName = MSIE;
217 try
218 {
219 browserVersion = toFloat(userAgentString
220 .substring(versionStartIndex, versionEndIndex));
221 }
222 catch (NumberFormatException e)
223 {
224 // Just use the default value.
225 }
226
227 // PHP code
228 // $Browser_Name = "MSIE";
229 // $Browser_Version = strtok("MSIE");
230 // $Browser_Version = strtok(" ");
231 // $Browser_Version = strtok(";");
232 }
233
234 // Opera isn't completely honest, either...
235 // Modificaton by Chris Mospaw <mospaw@polk-county.com>
236 if (userAgentString.indexOf(OPERA) != -1)
237 {
238 // Ex: Mozilla/4.0 (Windows NT 4.0;US) Opera 3.61 [en]
239 // Ex: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.02
240 versionStartIndex = (userAgentString.indexOf(OPERA)
241 + OPERA.length() + 1);
242 versionEndIndex = userAgentString.indexOf(" ", versionStartIndex);
243 if (versionEndIndex == -1)
244 {
245 versionEndIndex = userAgentString.length();
246 }
247
248 browserName = OPERA;
249 try
250 {
251 browserVersion = toFloat(userAgentString
252 .substring(versionStartIndex, versionEndIndex));
253 }
254 catch (NumberFormatException e)
255 {
256 // Just use the default value.
257 }
258
259 // PHP code
260 // $Browser_Name = "Opera";
261 // $Browser_Version = strtok("Opera");
262 // $Browser_Version = strtok("/");
263 // $Browser_Version = strtok(";");
264 }
265
266
267 // Try to figure out what platform.
268 if ((userAgentString.indexOf("Windows") != -1)
269 || (userAgentString.indexOf("WinNT") != -1)
270 || (userAgentString.indexOf("Win98") != -1)
271 || (userAgentString.indexOf("Win95") != -1))
272 {
273 browserPlatform = WINDOWS;
274 }
275
276 if (userAgentString.indexOf("Mac") != -1)
277 {
278 browserPlatform = MACINTOSH;
279 }
280
281 if (userAgentString.indexOf("X11") != -1)
282 {
283 browserPlatform = UNIX;
284 }
285
286 if (browserPlatform == WINDOWS)
287 {
288 if (browserName.equals(MOZILLA))
289 {
290 if (browserVersion >= 3.0)
291 {
292 javascriptOK = true;
293 fileUploadOK = true;
294 }
295 if (browserVersion >= 4.0)
296 {
297 cssOK = true;
298 }
299 }
300 else if (browserName == MSIE)
301 {
302 if (browserVersion >= 4.0)
303 {
304 javascriptOK = true;
305 fileUploadOK = true;
306 cssOK = true;
307 }
308 }
309 else if (browserName == OPERA)
310 {
311 if (browserVersion >= 3.0)
312 {
313 javascriptOK = true;
314 fileUploadOK = true;
315 cssOK = true;
316 }
317 }
318 }
319 else if (browserPlatform == MACINTOSH)
320 {
321 if (browserName.equals(MOZILLA))
322 {
323 if (browserVersion >= 3.0)
324 {
325 javascriptOK = true;
326 fileUploadOK = true;
327 }
328 if (browserVersion >= 4.0)
329 {
330 cssOK = true;
331 }
332 }
333 else if (browserName == MSIE)
334 {
335 if (browserVersion >= 4.0)
336 {
337 javascriptOK = true;
338 fileUploadOK = true;
339 }
340 if (browserVersion > 4.0)
341 {
342 cssOK = true;
343 }
344 }
345 }
346 else if (browserPlatform == UNIX)
347 {
348 if (browserName.equals(MOZILLA))
349 {
350 if (browserVersion >= 3.0)
351 {
352 javascriptOK = true;
353 fileUploadOK = true;
354 }
355 if (browserVersion >= 4.0)
356 {
357 cssOK = true;
358 }
359 }
360 }
361 }
362
363 /**
364 * Helper method to convert String to a float.
365 *
366 * @param s A String.
367 * @return The String converted to float.
368 */
369 private static final float toFloat(String s)
370 {
371 return Float.valueOf(s).floatValue();
372 }
373
374 }