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    }