001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * -----------------------------------------------------------------------------
005: * ivata masks may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * -----------------------------------------------------------------------------
030: * $Log: Browser.java,v $
031: * Revision 1.6 2005/10/11 18:54:06 colinmacleod
032: * Fixed some checkstyle and javadoc issues.
033: *
034: * Revision 1.5 2005/10/03 10:17:25 colinmacleod
035: * Fixed some style and javadoc issues.
036: *
037: * Revision 1.4 2005/10/02 14:06:32 colinmacleod
038: * Added/improved log4j logging.
039: *
040: * Revision 1.3 2005/09/14 12:53:46 colinmacleod
041: * Improved interface for browser type
042: * checking. Now uses <code>is...</code>
043: * methods (rather than accessing
044: * <code>type</code> directly.
045: *
046: * Revision 1.2 2005/04/09 18:04:17 colinmacleod
047: * Changed copyright text to GPL v2 explicitly.
048: *
049: * Revision 1.1 2005/01/06 23:00:12 colinmacleod
050: * Moved up a version number.
051: * Changed copyright notices to 2005.
052: * Updated the documentation:
053: * - started working on multiproject:site docu.
054: * - changed the logo.
055: * Added checkstyle and fixed LOADS of style issues.
056: * Added separate thirdparty subproject.
057: * Added struts (in web), util and webgui (in webtheme) from ivata op.
058: *
059: * Revision 1.3 2004/03/21 21:16:35 colinmacleod
060: * Shortened name to ivata op.
061: *
062: * Revision 1.2 2004/02/01 22:07:31 colinmacleod
063: * Added full names to author tags
064: *
065: * Revision 1.1.1.1 2004/01/27 20:59:38 colinmacleod
066: * Moved ivata op to SourceForge.
067: *
068: * Revision 1.2 2003/10/16 15:43:03 jano
069: * fixing problems with building and some problems with splitting to subprojects
070: *
071: * Revision 1.1.1.1 2003/10/13 20:49:28 colin
072: * Restructured portal into subprojects
073: *
074: * Revision 1.1 2003/02/24 19:33:32 colin
075: * Moved to new project.
076: *
077: * Revision 1.3 2003/02/04 17:43:46 colin
078: * Copyright notice
079: *
080: * Revision 1.2 2003/01/18 20:19:16 colin
081: * improved handling of opera including accurate recognition
082: * (even when opera pretends to be something else) and version numbers
083: *
084: * Revision 1.1 2002/09/16 13:52:48 colin
085: * Added browser class with checking for browser type, (i)frames.
086: * support and JavaScript.
087: * -----------------------------------------------------------------------------
088: */
089: package com.ivata.mask.web.browser;
090:
091: import org.apache.log4j.Logger;
092:
093: import com.ivata.mask.util.StringHandling;
094:
095: /**
096: * <p>
097: * This class identifies the capabilities of the web browser the client is
098: * using, from the user agent string.
099: * </p>
100: *
101: * <p>
102: * <code>LoginTag</code> creates an instance of this class in the http
103: * session, storing it under the attribute name <i>"browser" </i>.
104: * </p>
105: *
106: * @since ivata masks 0.4 (2002-09-12)
107: * @author Colin MacLeod
108: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
109: * @version $Revision: 1.6 $
110: */
111: public class Browser {
112: /**
113: * Logger for this class.
114: */
115: private static final Logger logger = Logger
116: .getLogger(Browser.class);
117:
118: /**
119: * <copyDoc>Refer to {@link #getJavaScriptVersion()</copyDoc>}.
120: */
121: private String javaScriptVersion = null;
122: /**
123: * <copyDoc>Refer to {@link #getType}.</copyDoc>
124: */
125: private Integer type;
126: /**
127: * <copyDoc>Refer to {@link #getUserAgent}.</copyDoc>
128: */
129: private String userAgent = null;
130: /**
131: * <copyDoc>Refer to {@link #getVersion}.</copyDoc>
132: */
133: private String version = null;
134:
135: /**
136: * <p>
137: * Construct an instance of the browser, using the user agent string
138: * provided to detect the browser's capabilities.
139: * </p>
140: *
141: * @param userAgentParam
142: * <copyDoc>Refer to {@link #getUserAgent()</copyDoc>}.
143: * @param javaScriptVersionParam
144: * <copyDoc>Refer to {@link #getJavaScriptVersion()</copyDoc>}.
145: */
146: public Browser(final String userAgentParam,
147: final String javaScriptVersionParam) {
148: this .javaScriptVersion = javaScriptVersionParam;
149: // call the setter as it actually handles the browser detection
150: setUserAgent(userAgentParam);
151: }
152:
153: /**
154: * <p>
155: * Detect whether or not the browser can display frames.
156: * </p>
157: *
158: * @return <code>true</code> if the browser can display frames, otherwise
159: * <code>false</code>.
160: */
161: public final boolean canDisplayFrames() {
162: if (logger.isDebugEnabled()) {
163: logger.debug("canDisplayFrames() - start");
164: }
165:
166: if (type.equals(BrowserConstants.TYPE_GALEON)
167: || type.equals(BrowserConstants.TYPE_KONQUEROR)
168: || type.equals(BrowserConstants.TYPE_LYNX)
169: || type.equals(BrowserConstants.TYPE_MOZILLA)
170: || type.equals(BrowserConstants.TYPE_OPERA)) {
171: if (logger.isDebugEnabled()) {
172: logger
173: .debug("canDisplayFrames() - end - return value = " + true);
174: }
175: return true;
176: } else if (type.equals(BrowserConstants.TYPE_INTERNET_EXPLORER)) {
177: boolean returnboolean = (version.compareTo("3") >= 0);
178: if (logger.isDebugEnabled()) {
179: logger
180: .debug("canDisplayFrames() - end - return value = "
181: + returnboolean);
182: }
183: return returnboolean;
184: } else if (type.equals(BrowserConstants.TYPE_NETSCAPE)) {
185: boolean returnboolean = (version.compareTo("2") >= 0);
186: if (logger.isDebugEnabled()) {
187: logger
188: .debug("canDisplayFrames() - end - return value = "
189: + returnboolean);
190: }
191: return returnboolean;
192: } else {
193: if (logger.isDebugEnabled()) {
194: logger
195: .debug("canDisplayFrames() - end - return value = " + false);
196: }
197: return false;
198: }
199: }
200:
201: /**
202: * <p>
203: * Detect whether or not the browser can display <code><iframe&bt;</code>
204: * tags.
205: * </p>
206: *
207: * @return <code>true</code> if the browser can display iframes, otherwise
208: * <code>false</code>.
209: */
210: public final boolean canDisplayIFrames() {
211: if (logger.isDebugEnabled()) {
212: logger.debug("canDisplayIFrames() - start");
213: }
214:
215: if (type.equals(BrowserConstants.TYPE_GALEON)
216: || type.equals(BrowserConstants.TYPE_MOZILLA)) {
217: if (logger.isDebugEnabled()) {
218: logger
219: .debug("canDisplayIFrames() - end - return value = " + true);
220: }
221: return true;
222: } else if (type.equals(BrowserConstants.TYPE_OPERA)) {
223: boolean returnboolean = (version.compareTo("5") >= 0);
224: if (logger.isDebugEnabled()) {
225: logger
226: .debug("canDisplayIFrames() - end - return value = "
227: + returnboolean);
228: }
229: return returnboolean;
230: } else if (type.equals(BrowserConstants.TYPE_INTERNET_EXPLORER)) {
231: boolean returnboolean = (version.compareTo("3") >= 0);
232: if (logger.isDebugEnabled()) {
233: logger
234: .debug("canDisplayIFrames() - end - return value = "
235: + returnboolean);
236: }
237: return returnboolean;
238: } else if (type.equals(BrowserConstants.TYPE_NETSCAPE)) {
239: boolean returnboolean = (version.compareTo("6") >= 0);
240: if (logger.isDebugEnabled()) {
241: logger
242: .debug("canDisplayIFrames() - end - return value = "
243: + returnboolean);
244: }
245: return returnboolean;
246: } else {
247: if (logger.isDebugEnabled()) {
248: logger
249: .debug("canDisplayIFrames() - end - return value = " + false);
250: }
251: return false;
252: }
253: }
254:
255: /**
256: * <p>
257: * Detect whether or not the browser can display
258: * <code><marquee&bt;</code> tags.
259: * </p>
260: *
261: * @return <code>true</code> if the browser can display marquee, otherwise
262: * <code>false</code>.
263: */
264: public final boolean canDisplayMarquee() {
265: if (logger.isDebugEnabled()) {
266: logger.debug("canDisplayMarquee() - start");
267: }
268:
269: if (type.equals(BrowserConstants.TYPE_GALEON)
270: || type.equals(BrowserConstants.TYPE_MOZILLA)) {
271: if (logger.isDebugEnabled()) {
272: logger
273: .debug("canDisplayMarquee() - end - return value = " + true);
274: }
275: return true;
276: } else if (type.equals(BrowserConstants.TYPE_INTERNET_EXPLORER)) {
277: boolean returnboolean = (version.compareTo("3") >= 0);
278: if (logger.isDebugEnabled()) {
279: logger
280: .debug("canDisplayMarquee() - end - return value = "
281: + returnboolean);
282: }
283: return returnboolean;
284: } else if (type.equals(BrowserConstants.TYPE_NETSCAPE)) {
285: boolean returnboolean = (version.compareTo("6") >= 0);
286: if (logger.isDebugEnabled()) {
287: logger
288: .debug("canDisplayMarquee() - end - return value = "
289: + returnboolean);
290: }
291: return returnboolean;
292: } else {
293: if (logger.isDebugEnabled()) {
294: logger
295: .debug("canDisplayMarquee() - end - return value = " + false);
296: }
297: return false;
298: }
299: }
300:
301: /**
302: * <p>
303: * A String depicting the version number of the JavaScript this browser
304: * supports if supported, otherwise <code>null</code> if the browser
305: * doesn't support JavaScript.
306: * </p>
307: *
308: * @return the current value of javaScriptVersion.
309: */
310: public String getJavaScriptVersion() {
311: if (logger.isDebugEnabled()) {
312: logger.debug("getJavaScriptVersion() - start");
313: }
314:
315: if (logger.isDebugEnabled()) {
316: logger
317: .debug("getJavaScriptVersion() - end - return value = "
318: + javaScriptVersion);
319: }
320: return javaScriptVersion;
321: }
322:
323: /**
324: * <p>
325: * Initialized by the constructor, this is the user agent string from the
326: * <code>request.getHeader("User-Agent")</code> value.
327: * </p>
328: *
329: * @return the current value of userAgent.
330: */
331: public String getUserAgent() {
332: if (logger.isDebugEnabled()) {
333: logger.debug("getUserAgent() - start");
334: }
335:
336: if (logger.isDebugEnabled()) {
337: logger.debug("getUserAgent() - end - return value = "
338: + userAgent);
339: }
340: return userAgent;
341: }
342:
343: /**
344: * <p>
345: * A string depiction of the browser version number if available and known,
346: * otherwise <code>null</code> if the browser manufacturer could not be
347: * identified.
348: * </p>
349: *
350: * @return the current value of version.
351: */
352: public String getVersion() {
353: if (logger.isDebugEnabled()) {
354: logger.debug("getVersion() - start");
355: }
356:
357: if (logger.isDebugEnabled()) {
358: logger.debug("getVersion() - end - return value = "
359: + version);
360: }
361: return version;
362: }
363:
364: /**
365: * Detect whether or not this browser is a flavor of Firefox.
366: *
367: * @return <code>true</code> if this is Firefox.
368: */
369: public boolean isFirefox() {
370: if (logger.isDebugEnabled()) {
371: logger.debug("isFirefox() - start");
372: }
373:
374: boolean returnboolean = BrowserConstants.TYPE_MOZILLA
375: .equals(type)
376: && (userAgent.indexOf("Firefox") != -1);
377: if (logger.isDebugEnabled()) {
378: logger.debug("isFirefox() - end - return value = "
379: + returnboolean);
380: }
381: return returnboolean;
382: }
383:
384: /**
385: * Detect whether or not this browser is a flavor of IE.
386: *
387: * @return <code>true</code> if this is IE.
388: */
389: public boolean isInternetExplorer() {
390: if (logger.isDebugEnabled()) {
391: logger.debug("isInternetExplorer() - start");
392: }
393:
394: boolean returnboolean = BrowserConstants.TYPE_INTERNET_EXPLORER
395: .equals(type);
396: if (logger.isDebugEnabled()) {
397: logger.debug("isInternetExplorer() - end - return value = "
398: + returnboolean);
399: }
400: return returnboolean;
401: }
402:
403: /**
404: * <p>
405: * Detect whether or not this browser is capable of displaying JavaScript,
406: * and has JavaScript enabled.
407: * </p>
408: *
409: * @return <code>true</code> if the browser can display JavaScript,
410: * otherwise <code>false</code>.
411: */
412: public boolean isJavaScriptEnabled() {
413: if (logger.isDebugEnabled()) {
414: logger.debug("isJavaScriptEnabled() - start");
415: }
416:
417: boolean returnboolean = (javaScriptVersion != null);
418: if (logger.isDebugEnabled()) {
419: logger
420: .debug("isJavaScriptEnabled() - end - return value = "
421: + returnboolean);
422: }
423: return returnboolean;
424: }
425:
426: /**
427: * Detect whether or not this browser is a flavor of Mozilla, though not
428: * Firefox.
429: *
430: * @return <code>true</code> if this is Mozilla.
431: */
432: public boolean isMozilla() {
433: if (logger.isDebugEnabled()) {
434: logger.debug("isMozilla() - start");
435: }
436:
437: boolean returnboolean = BrowserConstants.TYPE_MOZILLA
438: .equals(type)
439: && (userAgent.indexOf("Firefox") == -1);
440: if (logger.isDebugEnabled()) {
441: logger.debug("isMozilla() - end - return value = "
442: + returnboolean);
443: }
444: return returnboolean;
445: }
446:
447: /**
448: * Detect whether or not this browser is a flavor of Netscape.
449: *
450: * @return <code>true</code> if this is Netscape.
451: */
452: public boolean isNetscape() {
453: if (logger.isDebugEnabled()) {
454: logger.debug("isNetscape() - start");
455: }
456:
457: boolean returnboolean = BrowserConstants.TYPE_NETSCAPE
458: .equals(type);
459: if (logger.isDebugEnabled()) {
460: logger.debug("isNetscape() - end - return value = "
461: + returnboolean);
462: }
463: return returnboolean;
464: }
465:
466: /**
467: * Detect whether or not this browser is a flavor of Opera.
468: *
469: * @return <code>true</code> if this is Opera.
470: */
471: public boolean isOpera() {
472: if (logger.isDebugEnabled()) {
473: logger.debug("isOpera() - start");
474: }
475:
476: boolean returnboolean = BrowserConstants.TYPE_OPERA
477: .equals(type);
478: if (logger.isDebugEnabled()) {
479: logger.debug("isOpera() - end - return value = "
480: + returnboolean);
481: }
482: return returnboolean;
483: }
484:
485: /**
486: * <copyDoc>Refer to {@link #getJavaScriptVersion}.</copyDoc>
487: *
488: * @param javaScriptVersionParam
489: * <copyDoc>Refer to {@link #getJavaScriptVersion}.</copyDoc>
490: */
491: public final void setJavaScriptVersion(
492: final String javaScriptVersionParam) {
493: if (logger.isDebugEnabled()) {
494: logger
495: .debug("setJavaScriptVersion(String javaScriptVersionParam = "
496: + javaScriptVersionParam + ") - start");
497: }
498:
499: this .javaScriptVersion = javaScriptVersionParam;
500:
501: if (logger.isDebugEnabled()) {
502: logger.debug("setJavaScriptVersion(String) - end");
503: }
504: }
505:
506: /**
507: * <copyDoc>Refer to {@link #getType}.</copyDoc>
508: *
509: * @param typeParam
510: * <copyDoc>Refer to {@link #getType}.</copyDoc>
511: */
512: public final void setType(final Integer typeParam) {
513: if (logger.isDebugEnabled()) {
514: logger.debug("setType(Integer typeParam = " + typeParam
515: + ") - start");
516: }
517:
518: this .type = typeParam;
519:
520: if (logger.isDebugEnabled()) {
521: logger.debug("setType(Integer) - end");
522: }
523: }
524:
525: /**
526: * <copyDoc>Refer to {@link #getUserAgent}.</copyDoc>
527: *
528: * @param userAgentParam
529: * <copyDoc>Refer to {@link #getUserAgent}.</copyDoc>
530: */
531: public final void setUserAgent(final String userAgentParam) {
532: if (logger.isDebugEnabled()) {
533: logger.debug("setUserAgent(String userAgentParam = "
534: + userAgentParam + ") - start");
535: }
536:
537: // convert null to empty string - easier to deal with :-)
538: if (StringHandling.isNullOrEmpty(userAgentParam)) {
539: this .userAgent = "";
540: } else {
541: this .userAgent = userAgentParam;
542: }
543: this .version = null;
544: // first let's find opera - it pretends to be everyone else too!
545: int position;
546: // first let's find opera - it pretends to be everyone else too!
547: int start;
548: // first let's find opera - it pretends to be everyone else too!
549: int end;
550: if ((position = userAgent.indexOf("Opera")) != -1) {
551: this .type = BrowserConstants.TYPE_OPERA;
552: // sometimes there is a slash sometimes just a space after 'Opera'
553: // either way, relative to the start of 'Opera', it is the same
554: start = position + "Opera".length() + 1;
555: end = userAgent.indexOf(" ", start);
556: if ((start != -1) && (end != -1)) {
557: this .version = userAgent.substring(start, end);
558: }
559: } else if ((position = userAgent.indexOf("Galeon")) != -1) {
560: this .type = BrowserConstants.TYPE_GALEON;
561: start = userAgent.indexOf("/", position);
562: end = userAgent.indexOf(" ", start);
563: if ((start != -1) && (end != -1)) {
564: this .version = userAgent.substring(++start, end);
565: }
566: } else if (userAgent.indexOf("Gecko") != -1) {
567: // see if it is (old) Netscape
568: if ((position = userAgent.indexOf("Netscape")) != -1) {
569: this .type = BrowserConstants.TYPE_NETSCAPE;
570: start = userAgent.indexOf("/", position);
571: end = userAgent.indexOf(" ", start);
572: if ((start != -1) && (end != -1)) {
573: this .version = userAgent.substring(++start, end);
574: }
575: } else {
576: // treat all other Gecko browsers as Mozilla
577: this .type = BrowserConstants.TYPE_MOZILLA;
578: String rv = "rv:";
579: start = userAgent.indexOf(rv, position);
580: end = userAgent.indexOf(")", start);
581: if ((start != -1) && (end != -1)) {
582: start += rv.length();
583: this .version = userAgent.substring(start, end);
584: } else {
585: // just default to 0 for Mozilla
586: this .version = "0";
587: }
588: }
589: } else if ((userAgent.indexOf("Nav") != -1)
590: || (userAgent.indexOf("Gold") != -1)
591: || (userAgent.indexOf("Netscape") != -1)) {
592: // good old fashioned navigator 4.x and earlier
593: this .type = BrowserConstants.TYPE_NETSCAPE;
594: } else if ((position = userAgent.indexOf("MSIE")) != -1) {
595: // Internet Explorer
596: this .type = BrowserConstants.TYPE_INTERNET_EXPLORER;
597: start = userAgent.indexOf(" ", position);
598: end = userAgent.indexOf(";", start);
599: if ((start != -1) && (end != -1)) {
600: this .version = userAgent.substring(++start, end);
601: } else {
602: // don't want to let this default to Mozilla number
603: // unlikely to be < 3.0 anyway!
604: this .version = "3.0";
605: }
606: } else if (userAgent.indexOf("Konq") != -1) {
607: this .type = BrowserConstants.TYPE_KONQUEROR;
608: } else if (userAgent.indexOf("Lynx") != -1) {
609: this .type = BrowserConstants.TYPE_LYNX;
610: } else if ((userAgent.indexOf("bot") != 1)
611: || (userAgent.indexOf("Google") != 1)
612: || (userAgent.indexOf("Slurp") != 1)
613: || (userAgent.indexOf("Scooter") != 1)
614: || (userAgent.indexOf("Spider") != 1)
615: || (userAgent.indexOf("Infoseek") != 1)) {
616: this .type = BrowserConstants.TYPE_ROBOT;
617: } else {
618: this .type = BrowserConstants.TYPE_UNKNOWN;
619: }
620: // if the version wasn't set above, set it to the string after the
621: // first slash, before the first space after that
622: if (this .version == null) {
623: start = userAgent.indexOf("/", position);
624: end = userAgent.indexOf(" ", start);
625: if ((start != -1) && (end != -1)) {
626: this .version = userAgent.substring(++start, end);
627: } else {
628: // default the version number to zero for alphanumeric
629: // comparisons
630: this .version = "0";
631: }
632: }
633:
634: if (logger.isDebugEnabled()) {
635: logger.debug("setUserAgent(String) - end");
636: }
637: }
638:
639: /**
640: * <copyDoc>Refer to {@link #getVersion()</copyDoc>}.
641: *
642: * @param versionParam
643: * <copyDoc>Refer to {@link #getVersion()</copyDoc>}.
644: */
645: public final void setVersion(final String versionParam) {
646: if (logger.isDebugEnabled()) {
647: logger.debug("setVersion(String versionParam = "
648: + versionParam + ") - start");
649: }
650:
651: this .version = versionParam;
652:
653: if (logger.isDebugEnabled()) {
654: logger.debug("setVersion(String) - end");
655: }
656: }
657: }
|