You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ck...@apache.org on 2009/09/30 20:54:22 UTC

svn commit: r820386 [1/2] - in /myfaces/commons/trunk: ./ myfaces-commons-agent/ myfaces-commons-agent/src/ myfaces-commons-agent/src/main/ myfaces-commons-agent/src/main/java/ myfaces-commons-agent/src/main/java/org/ myfaces-commons-agent/src/main/jav...

Author: ckormos
Date: Wed Sep 30 18:54:21 2009
New Revision: 820386

URL: http://svn.apache.org/viewvc?rev=820386&view=rev
Log:
applied patch for [MFCOMMONS-11] - New agent detection module (Thanks to Marius Petoi)

Added:
    myfaces/commons/trunk/myfaces-commons-agent/
    myfaces/commons/trunk/myfaces-commons-agent/pom.xml   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java   (with props)
    myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentImpl.java   (with props)
Modified:
    myfaces/commons/trunk/pom.xml

Added: myfaces/commons/trunk/myfaces-commons-agent/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/pom.xml?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/pom.xml (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/pom.xml Wed Sep 30 18:54:21 2009
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    * Licensed to the Apache Software Foundation (ASF) under one or more
+    * contributor license agreements.  See the NOTICE file distributed with
+    * this work for additional information regarding copyright ownership.
+    * The ASF licenses this file to You under the Apache License, Version 2.0
+    * (the "License"); you may not use this file except in compliance with
+    * the License.  You may obtain a copy of the License at
+    *
+    *      http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+        <parent>
+            <groupId>org.apache.myfaces.commons</groupId>
+            <artifactId>commons12</artifactId>
+            <version>1.0.1-SNAPSHOT</version>
+        </parent>
+
+	<artifactId>myfaces-commons-agent</artifactId>
+	<packaging>jar</packaging>
+	<version>1.0.0-SNAPSHOT</version>
+	<name>Apache MyFaces Commons Agent Detection</name>
+	<description>MyFaces Commons Agent Detection provides and API obtaining information about the agent accessing a JSF application</description>
+	
+	<dependencies>				
+		<dependency>
+			<groupId>org.apache.myfaces.core</groupId>
+			<artifactId>myfaces-api</artifactId>	
+			<scope>compile</scope>
+		</dependency>		
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.5</source>
+					<target>1.5</target>
+				</configuration>
+			</plugin>
+            <plugin>
+                <!-- Install in the repository a "-javadoc.jar" file -->
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.4</version>
+                <executions>
+                    <execution>
+                        <id>attach-javadoc</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <!-- Install in the repository a "-sources.jar" file -->
+                <artifactId>maven-source-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-source</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+		</plugins>
+	</build>
+</project>

Propchange: myfaces/commons/trunk/myfaces-commons-agent/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/pom.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+import java.util.Map;
+
+/**
+ * The Agent interface describes the client that is making the request that will display
+ * the rendered output.
+ * <p>
+ * Implementations that provide the set of capabilities must clearly define the names
+ * of these capabilities and their values.
+ * </p>
+ * <p/>
+ * Capability names that are implementation private must be defined so using appropriate
+ * naming schemes. Trinidad private capability names are prefixed using "-adfinternal-xxx",
+ * and such capability names (and their values) may change at anytime
+ * (and not guaranteed to be supported in future releases).
+ * <p/>
+ */
+
+public interface Agent {
+
+    /**
+     * @return return the Type of Agent. Returns <code>TYPE_UNKNOWN</code> if not available.
+     *         <br>E.g. desktop, pda, phone
+     */
+    public String getType();
+
+    /**
+     * @return return the canonical name of the agent (browser application).
+     *         Returns <code>null</code> if not available.
+     *         <br>E.g. gecko, ie, opera, pocketie
+     */
+    public String getAgentName();
+
+    /**
+     * @return return the version number of the agent (browser application).
+     *         Return <code>null</code> if not available.
+     */
+    public String getAgentVersion();
+
+    /**
+     * @return return the canonical name for the platform. Returns <code>null</code> if not available.
+     *         <br>E.g ppc, series60, windows, mac, linux, solaris
+     */
+    public String getPlatformName();
+
+    /**
+     * @return return the version number for the platform.
+     *         Returns <code>null</code> if not available.
+     */
+    public String getPlatformVersion();
+
+    /**
+     * @return return a canonical name for the Hardware make and Model. Re
+     *         turns <code>null</code> if not available.
+     *         <br>E.g nokia6600, sonyericssonP900, nokai3650i
+     */
+    public String getHardwareMakeModel();
+
+
+    /**
+     * @return Map of capability names and their values for the current client request.
+     *         <br>Some of the available capability names are:
+     *         <br><i>height</i>- provides the screen height in pixels of the Agent as an Integer.
+     *         <br><i>width</i>- provides the screen width in pixels of the Agent as an Integer.
+     *         <br><i>dom</i>- provides the DOM API support of the agent as a String.
+     *         Possible values are: <i>level2</i>, <i>level1</i>, <i>form</i>, and <i>none</i>.
+     *         <br><i>frames</i>- returns a Boolean value signifying whether or not the Agent
+     *         supports frames.
+     *         <br><i>accessKeys</i>- returns a Boolean value signifying whether or not the Agent
+     *         supports accessKeys.
+     */
+    // See CapabilityMap for why this takes Object as a key instead
+    // of String, at least for now
+    public Map<Object, Object> getCapabilities();
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/Agent.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+import org.apache.myfaces.commons.agent.impl.AgentFactoryImpl;
+
+/**
+ * Class which contains all constants related to the detection of the agent
+ */
+public class AgentConstants {
+
+    /**
+     * Prevent instantiation of constants class
+     */
+    private AgentConstants() {
+    }
+
+    /**
+     * The factory used for creating an agent.
+     * <p/>
+     * TODO: see whether it is ok to put the factory here.
+     */
+    public static final AgentFactory FACTORY = AgentFactoryImpl.getInstance();
+
+    /**
+     * Constant for an unknown element (type, platform, etc).
+     */
+    public static final String UNKNOWN = "unknown";
+
+    /**
+     * Constant for telnet device type
+     */
+    public static final String TYPE_TELNET = "telnet";
+
+    /**
+     * Constant for desktop devices
+     */
+    public static final String TYPE_DESKTOP = "desktop";
+
+    /**
+     * Constant for hand-held sized devices (Pocket-PC, Palm)
+     */
+    public static final String TYPE_PDA = "pda";
+
+    /**
+     * Constant for Phone sized devices
+     */
+    public static final String TYPE_PHONE = "phone";
+
+    /**
+     * Constant for windows platform
+     */
+    public static final String PLATFORM_WINDOWS = "windows";
+
+    /**
+     * Constant for linux platform
+     */
+    public static final String PLATFORM_LINUX = "linux";
+
+    /**
+     * Constant for MacOS platform
+     */
+    public static final String PLATFORM_MACOS = "mac";
+
+    /**
+     * Constant for Mac platform
+     *
+     * @deprecated
+     */
+    @Deprecated
+    public static final String PLATFORM_MAC = PLATFORM_MACOS;
+
+    /**
+     * Constant for iPhone platform
+     */
+    public static final String PLATFORM_IPHONE = "iphone";
+
+    /**
+     * Constant for plam platform
+     */
+    public static final String PLATFORM_PALM = "palm";
+
+    /**
+     * Constant for solaris platform
+     */
+    public static final String PLATFORM_SOLARIS = "solaris";
+
+    /**
+     * Constant for pocket pc platform
+     */
+    public static final String PLATFORM_PPC = "ppc";
+
+    /**
+     * Constant for blackberry platform
+     */
+    public static final String PLATFORM_BLACKBERRY = "blackberry";
+
+    /**
+     * /** Constant for Nokia S60 platform
+     */
+    public static final String PLATFORM_NOKIA_S60 = "nokia_s60";
+
+    /**
+     * Constant for generic PDA device browser
+     */
+    public static final String PLATFORM_GENERICPDA = "genericpda";
+
+    /**
+     * Constant for Konqueror agent
+     */
+    public static final String AGENT_KONQUEROR = "konqueror";
+
+    /**
+     * Constant for Internet Explorer agent
+     */
+    public static final String AGENT_IE = "ie";
+
+    /**
+     * Constant for Gecko agent. Used for all Gecko based agents like Mozilla,
+     * Netscape 6+
+     */
+    public static final String AGENT_GECKO = "gecko";
+
+    /**
+     * Constant for email agent. Used for all email agents like Outlook 2007 and
+     * Thunderbird
+     */
+    public static final String AGENT_EMAIL = "email";
+
+    /**
+     * Constant for Apple Webkit agent. Used for all Webkit based agent like
+     * Safari
+     */
+    public static final String AGENT_WEBKIT = "webkit";
+
+    /**
+     * Constant for BlackBerry Browser agent. (Note the distinction from the
+     * BlackBerry platform. The BlackBerry Browser agent runs on the BlackBerry
+     * platform. It is possible for other agents to run on the BlackBerry
+     * platform.)
+     */
+    public static final String AGENT_BLACKBERRY = "blackberry";
+
+    /**
+     * Constant for Symbian Nokia S60 agent. Used for Nokia Series 60 3rd
+     * Edition or later
+     */
+    public static final String AGENT_NOKIA_S60 = "nokia_s60";
+
+    /**
+     * Constant for basic HTML (without JavaScript) Browser agent.
+     */
+    public static final String AGENT_GENERICPDA = "genericpda";
+
+    /**
+     * Name Constant for Netfront agent
+     */
+    public static final String AGENT_NETFRONT = "netfront";
+
+    /**
+     * Name Constant for Netscape agent. Used only for Netscape versions that
+     * are not Gecko based such as Netscape 4.7
+     */
+    public static final String AGENT_NETSCAPE = "netscape";
+
+    /**
+     * Name Constant for Palm Webpro agent //@TODO: Check: Isn't webpro same as
+     * netfront access
+     */
+    public static final String AGENT_WEBPRO = "webpro";
+
+    /**
+     * Name constant for ICE browser agent
+     */
+    public static final String AGENT_ICE_BROWSER = "icebrowser";
+
+    /**
+     * Name Constant for Pixo agent //@TODO: Check: Are we still supporting
+     * Pixo??
+     */
+    public static final String AGENT_PIXO = "pixo";
+
+    /**
+     * Name Constant for OracleAS Wireless. //@TODO: Check: Do we still have to
+     * support this??
+     */
+    public static final String AGENT_PTG = "ptg";
+
+    /**
+     * Name Constant for Blazer agent
+     */
+    public static final String AGENT_BLAZER = "blazer";
+
+    /**
+     * Name Constant for Xiino agent
+     */
+    public static final String AGENT_XIINO = "xiino";
+
+    /**
+     * Name Constant for Palm Web clipping (Elaine) agent
+     */
+    public static final String AGENT_ELAINE = "elaine";
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentConstants.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+import org.apache.myfaces.commons.agent.Agent;
+
+import java.util.Map;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * Factory to create Agent. Allows implementations to plug in their own agent
+ * detection, without having to override RequestContext.
+ * //@todo: Right now this not public API, but will be when adf faces cofiguration is sorted out
+ */
+
+public interface AgentFactory {
+    /**
+     * @param facesContext
+     * @return Agent for the current request/context
+     */
+    public Agent createAgent(FacesContext facesContext);
+
+    /**
+     * @param headerMap
+     * @return
+     */
+    public Agent createAgent(Map<String, String> headerMap);
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/AgentFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+
+/**
+ * Class which declares all constants used as capability keys.
+ */
+public class CapabilityConstants {
+
+    /**
+     * Prevent instantiation of constants class
+     */
+    private CapabilityConstants() {
+    }
+
+    static public final CapabilityKey CAP_WIDTH = CapabilityKey
+            .getCapabilityKey("width", true);
+
+    static public final CapabilityKey CAP_HEIGHT = CapabilityKey
+            .getCapabilityKey("height", true);
+
+    static public final CapabilityKey CAP_IS_JDEV_JAVASCRIPT_VE = CapabilityKey
+            .getCapabilityKey("-adfinternal-isJDevJavascriptVE", true);
+
+    static public final CapabilityKey CAP_IS_JDEV_VE = CapabilityKey
+            .getCapabilityKey("-adfinternal-isJDevVE", true);
+
+    /**
+     * If this capability flag is true, it means that the request is from an
+     * agent that is running in a narrow-screen PDA. Trinidad optimizes its
+     * rendering for narrow-screen PDAs to reduce the overall width of the page
+     * rendered.
+     */
+    static public final CapabilityKey CAP_NARROW_SCREEN = CapabilityKey
+            .getCapabilityKey("narrowScreen", true);
+
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityConstants.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+import java.util.HashMap;
+
+/**
+ * Key for capability Pretty much an impl similar to uix of AgentCapabilityKey
+ * -- added method getKeyAt (and required storage units) -- remove getKeyCount
+ * as ...
+ */
+public final class CapabilityKey {
+
+    private CapabilityKey(String capabilityName, int index) {
+        if (capabilityName == null)
+            throw new NullPointerException();
+
+        if (index < 0)
+            throw new IllegalArgumentException();
+
+        _capName = capabilityName.intern();
+        _capIndex = index;
+        _capKeyNames.put(_capName, this);
+
+        if (_keys.length < _capIndex) {
+            CapabilityKey[] newKeys = new CapabilityKey[_keys.length
+                    + DEFAULT_SIZE];
+            System.arraycopy(_keys, 0, newKeys, 0, _keys.length);
+        }
+
+        _keys[_capIndex] = this;
+    }
+
+    /**
+     * Create a new CapabilityKey. If an key with name already exists returns
+     * the pre-created CapabilityKey
+     *
+     * @param capabilityName
+     */
+    public static CapabilityKey getCapabilityKey(String capabilityName,
+                                                 boolean createIfNull) {
+        if (capabilityName == null)
+            return null;
+
+        Object key = _capKeyNames.get(capabilityName);
+        if ((createIfNull) && (key == null))
+            key = _createKey(capabilityName);
+
+        return ((CapabilityKey) key);
+    }
+
+    /**
+     * @param capabilityName
+     * @return CapabilityKey for the capability name
+     */
+    public static CapabilityKey getCapabilityKey(String capabilityName) {
+        return getCapabilityKey(capabilityName, false);
+    }
+
+    /**
+     * @return capability name
+     */
+    public String getCapabilityName() {
+        return _capName;
+    }
+
+    /**
+     * @return capability key index
+     */
+    public int getIndex() {
+        return _capIndex;
+    }
+
+    /**
+     * @param index
+     * @return CapabilityKey with the specified index
+     */
+    public static CapabilityKey getKeyAt(int index) {
+        if (index >= 0 && index <= _count)
+            return _keys[index];
+
+        // just return null if out of range
+        return null;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return this == obj;
+    }
+
+    @Override
+    public int hashCode() {
+        return _capIndex;
+    }
+
+    synchronized private static Object _createKey(String capabilityName) {
+        Object key = _capKeyNames.get(capabilityName);
+        if (key == null) {
+            key = new CapabilityKey(capabilityName, _count++);
+        }
+        return key;
+    }
+
+    @Override
+    public String toString() {
+        return _capName;
+    }
+
+    private String _capName;
+    private int _capIndex = 0;
+
+    static final private int DEFAULT_SIZE = 50;
+
+    static private HashMap<String, CapabilityKey> _capKeyNames = new HashMap<String, CapabilityKey>();
+    static private CapabilityKey[] _keys = new CapabilityKey[DEFAULT_SIZE];
+    private static int _count = 0;
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityKey.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+import java.util.Set;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.Collections;
+
+/**
+ * Pretty much the same Impl of UIX CapabilityMap, with following changes
+ * -- Actually a map implementation now
+ * -- added support to get Entries (To support a map interface)
+ * -- Also this impl assumes that the number of keys **will** change (increase) after init.
+ */
+// FIXME -= Simon Lessard =-
+//       This is another map that can accept both String and another type as keys.
+//       Shouldn't we force type safety with a single key type ?
+//       -= Adam Winer =-
+//       This, supports Strings and CapabilityKey.  In theory, using
+//       CapabilityKey is faster, which lets our built-in renderers
+//       execute faster.  A fair question is whether this is a real
+//       issue.  At the moment, however, it is definitely the case
+//       that we are using CapabilityKey inside our code, and yet we
+//       haven't made the plunge to require everyone to use
+//       CapabilityKey on Agent (or make CapabilityKey public).
+public class CapabilityMap extends AbstractMap<Object, Object> implements Cloneable {
+
+    private CapabilityMap() {
+    }
+
+    public CapabilityMap(Object[][] keyValuesArr) {
+
+        int arrayCount = keyValuesArr.length;
+        CapabilityKey[][] keyArrays = new CapabilityKey[arrayCount][];
+
+        for (int arrayIndex = 0; arrayIndex < arrayCount; arrayIndex++) {
+            keyArrays[arrayIndex] = new CapabilityKey[
+                    keyValuesArr[arrayIndex] == null ? 0 : (keyValuesArr[arrayIndex].length >> 1)];
+        }
+
+        //Get All the Keys
+        //determine how many keys we need. The keys list/count could change hence
+        //need to find max key index.
+        int maxKeyIndex = 0;
+        for (int arrayIndex = 0; arrayIndex < arrayCount; arrayIndex++) {
+            Object[] keyValues = keyValuesArr[arrayIndex];
+            CapabilityKey[] keys = keyArrays[arrayIndex];
+            int keyCount = keys.length;
+
+            for (int i = 0; i < keyCount; i++) {
+                keys[i] = (CapabilityKey) keyValues[i << 1];
+                maxKeyIndex = _max(keys[i].getIndex(), maxKeyIndex);
+            }
+        }
+
+        _indexedValues = new Object[maxKeyIndex + 1];
+        for (int arrayIndex = 0; arrayIndex < arrayCount; arrayIndex++) {
+            Object[] keyValues = keyValuesArr[arrayIndex];
+            CapabilityKey[] keys = keyArrays[arrayIndex];
+            int keyCount = keys.length;
+
+            for (int i = 0; i < keyCount; i++) {
+                _indexedValues[keys[i].getIndex()] = keyValues[(i << 1) + 1];
+            }
+        }
+    }
+
+
+    /**
+     * @param capKey
+     * @return value object for the capability
+     */
+    public Object getCapability(CapabilityKey capKey) {
+        int keyIndex = capKey.getIndex();
+
+        if (keyIndex < _indexedValues.length)
+            return _indexedValues[keyIndex];
+
+        return null;
+    }
+
+    /**
+     * @param capabilities
+     * @return returns a new capability map that merges key/values of the provided map
+     */
+    public CapabilityMap merge(Map<Object, Object> capabilities) {
+        if ((capabilities == null) || (capabilities.isEmpty()))
+            return this;
+
+        return merge(_getMapAsArray(capabilities));
+    }
+
+
+    /**
+     * @param capabilities
+     * @return
+     */
+    //Doing this as current Impl. uses this method
+    public CapabilityMap merge(Object[] capabilities) {
+        // could simply do this but .....
+        // new CapabilitiesImpl (new Object[][] {_getCapabilitiesAsArray(),
+        //                                       capabilities});
+
+        if ((capabilities == null) || (capabilities.length <= 0))
+            return this;
+
+        int maxKeyIndex = _indexedValues.length;
+        Object[] capKeys = new Object[capabilities.length >> 1];
+        Object[] capValues = new Object[capabilities.length >> 1];
+        for (int i = 0, j = 0; i < capabilities.length - 1; i++) {
+            CapabilityKey capKey = (CapabilityKey) capabilities[i++];
+            capKeys[j] = capKey;
+            capValues[j++] = capabilities[i];
+            maxKeyIndex = _max(capKey.getIndex(), maxKeyIndex);
+        }
+
+        //new structures
+        Object[] indexedValues = new Object[maxKeyIndex + 1];
+
+        //Copy the values
+        System.arraycopy(_indexedValues, 0, indexedValues, 0, _indexedValues.length);
+        for (int i = 0; i < capKeys.length; i++) {
+            CapabilityKey capKey = (CapabilityKey) capKeys[i];
+            int keyIndex = capKey.getIndex();
+            indexedValues[keyIndex] = capValues[i];
+        }
+
+        CapabilityMap newImpl = new CapabilityMap();
+        newImpl._indexedValues = indexedValues;
+        return newImpl;
+    }
+
+    //Implementation of Map Methods
+    /**
+     * @param key
+     * @return
+     */
+    @Override
+    public Object get(Object key) {
+        if (key == null)
+            return null;
+
+        if (key instanceof CapabilityKey)
+            return getCapability((CapabilityKey) key);
+
+        return _get(key.toString());
+    }
+
+    /**
+     * @param key
+     * @param value
+     * @return
+     */
+    @Override
+    public Object put(Object key, Object value) {
+        return new UnsupportedOperationException();
+    }
+
+    /**
+     * @return
+     */
+    @Override
+    public Set<Map.Entry<Object, Object>> entrySet() {
+        if (_entrySet == null)
+            _createEntrySet();
+
+        return _entrySet;
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            CapabilityMap that = (CapabilityMap) super.clone();
+            that._indexedValues = _indexedValues.clone();
+            that._entrySet = null;
+            return that;
+        }
+        catch (CloneNotSupportedException cnse) {
+            assert false;
+            return null;
+        }
+    }
+
+    private Object _get(String key) {
+        //key == null should be done before
+        CapabilityKey key0 = null;
+        Object value = null;
+        key0 = CapabilityKey.getCapabilityKey(key);
+        if (key0 != null)
+            value = getCapability(key0);
+
+        return value;
+    }
+
+
+    synchronized private void _createEntrySet() {
+        if (_entrySet == null) {
+            HashSet<Map.Entry<Object, Object>> hs =
+                    new HashSet<Map.Entry<Object, Object>>();
+            Iterator<Object> iter = new KeyIterator();
+            while (iter.hasNext()) {
+                CapabilityKey capKey = (CapabilityKey) iter.next();
+                Object value = getCapability(capKey);
+                CEntry ce = new CEntry(capKey.getCapabilityName(), value);
+                hs.add(ce);
+            }
+            //Don't allow clear(), remove(), etc etc on the map
+            _entrySet = Collections.unmodifiableSet(hs);
+        }
+    }
+
+
+    private int _max(int value1, int value2) {
+        return (value1 > value2 ? value1 : value2);
+    }
+
+
+    private Object[] _getMapAsArray(Map<Object, Object> capabilities) {
+        Object[] caps = new Object[capabilities.size() * 2];
+        int i = 0;
+        for (Map.Entry<Object, Object> entry : capabilities.entrySet()) {
+            Object key = entry.getKey();
+            CapabilityKey capKey = key instanceof CapabilityKey
+                    ? (CapabilityKey) key
+                    : CapabilityKey.getCapabilityKey((String) key);
+            caps[i++] = capKey;
+            caps[i++] = entry.getValue();
+        }
+        return caps;
+    }
+
+
+    //KeyIterator
+    private class KeyIterator implements Iterator<Object> {
+        public KeyIterator() {
+            _setNext();
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean hasNext() {
+            if (_next != null)
+                return true;
+            return false;
+        }
+
+        public Object next() {
+            if (_next == null)
+                _setNext();
+
+            if (_next != null) {
+                CapabilityKey next = _next;
+                _setNext();
+                return next;
+            }
+
+            throw new NoSuchElementException();
+        }
+
+        private void _setNext() {
+            _next = null;
+            for (int i = _current; i < _indexedValues.length; i++) {
+                if (_indexedValues[i] != null) {
+                    _next = CapabilityKey.getKeyAt(i);
+                    _current = ++i;
+                    break;
+                }
+            }
+        }
+
+        private int _current = 0;
+        private CapabilityKey _next = null;
+
+    }
+
+
+    //Map Entry
+    static private class CEntry implements Entry<Object, Object> {
+
+        private Object key;
+        private Object value;
+
+        CEntry(Object key, Object value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (!(o instanceof CEntry))
+                return false;
+
+            CEntry ce = (CEntry) o;
+            return ((ce.key == key || ce.key.equals(key)) &&
+                    (value == null ? ce.value == null : ce.value.equals(value)));
+        }
+
+        public Object getKey() {
+            return key;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public Object setValue(Object newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int hashCode() {
+            return key.hashCode() ^ (value == null ? 0 : value.hashCode());
+        }
+    }
+
+
+    private Object[] _indexedValues;
+    private Set<Map.Entry<Object, Object>> _entrySet;
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+import org.apache.myfaces.commons.agent.CapabilityKey;
+
+import java.util.HashMap;
+
+public class CapabilityValue {
+    //AdfFacesAgent (the old Agent) uses Objects constants for
+    //capability values, and the code base uses identity comaprison
+    //to check for a capability value.
+
+    //With the new Agent, the values are in a file and are string objects.
+    //So one way of making the identity comparison still work is to perform
+    //an string.intern() on the values read from the file.
+
+    //Also string values need to be retained, as need to support
+    //clients accessing the Agent Api (RequestContext object constants
+    //are internal impl)
+
+    //This is a poor man's quick substitute for string.intern().
+    //Later, need to refine this properly.
+    //Based on key, can know the value type object. Need metadata info on key
+
+    public final static Object getCapabilityValue(CapabilityKey key,
+                                                  Object value) {
+        if (value instanceof String) {
+            String stringValue = (String) value;
+            if (stringValue.length() == 0)
+                return null;
+            if (Character.isDigit(stringValue.charAt(0))) {
+                try {
+                    return Integer.valueOf(stringValue);
+                }
+                catch (NumberFormatException nfe) {
+                }
+            }
+
+            if ("true".equals(value))
+                return Boolean.TRUE;
+            else if ("false".equals(value))
+                return Boolean.FALSE;
+        }
+
+        return _getValue(value);
+    }
+
+    synchronized static private Object _getValue(Object value) {
+        Object cValue = _values.get(value);
+        if (cValue != null)
+            return cValue;
+
+        _values.put(value, value);
+        return value;
+    }
+
+    private static HashMap<Object, Object> _values = new HashMap<Object, Object>(32);
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/CapabilityValue.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent;
+
+/**
+ * Class that declares all constants used by the detection agent.
+ */
+public final class XhtmlAgentConstants {
+
+    // This class is only a container for constants, therefore it should not be instantiated
+    private XhtmlAgentConstants() {
+    }
+
+    // Maximum width of a narrow-screen PDA device in pixels
+    public static final int NARROW_SCREEN_PDA_MAX_WIDTH = 240;
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/XhtmlAgentConstants.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java?rev=820386&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java (added)
+++ myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java Wed Sep 30 18:54:21 2009
@@ -0,0 +1,900 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.myfaces.commons.agent.impl;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.faces.context.FacesContext;
+
+import static org.apache.myfaces.commons.agent.AgentConstants.*;
+import org.apache.myfaces.commons.agent.*;
+
+/**
+ * Default MyFaces implementation of AgentFactory.
+ */
+public class AgentFactoryImpl implements AgentFactory {
+
+    /**
+     * Unique instance of this factory.
+     */
+    private static AgentFactory _instance;
+
+    /**
+     * Factory is a singleton, therefore make constructor public.
+     */
+    private AgentFactoryImpl() {
+    }
+
+    /**
+     * @return the unique instance of this <code>AgentFactory</code>
+     */
+    public static AgentFactory getInstance() {
+        if (_instance == null) {
+            _instance = new AgentFactoryImpl();
+        }
+        return _instance;
+    }
+
+    public Agent createAgent(Map<String, String> headerMap) {
+        // this method primarily exists for use during testing
+
+        AgentImpl agent = new AgentImpl();
+        _populateAgentImpl(null, headerMap, agent);
+        return agent;
+    }
+
+    public Agent createAgent(FacesContext facesContext) {
+        AgentImpl agent = new AgentImpl();
+
+        // Get the RequestHeaderMap to help populate the agent
+        Map<String, String> headerMap;
+        if (facesContext != null) {
+            headerMap = facesContext.getExternalContext().getRequestHeaderMap();
+        } else {
+            headerMap = Collections.emptyMap();
+        }
+
+        // TODO: Add declarative and extensible means for populating AgentImpl
+        // object
+        // the RequestHeaderMap helps populate the agent
+        _populateAgentImpl(facesContext, headerMap, agent);
+
+        return agent;
+    }
+
+    // The headerMap is the RequestHeaderMap from the externalContext. It is
+    // consulted to correctly populate the agent
+    private void _populateAgentImpl(FacesContext facesContext,
+                                    Map<String, String> headerMap, AgentImpl agent) {
+
+        String userAgent = headerMap.get("User-Agent");
+        String isEmail = null;
+        if (facesContext != null)
+            isEmail = facesContext.getExternalContext()
+                    .getRequestParameterMap().get(_EMAIL_PARAM);
+
+        if ("true".equals(isEmail)) {
+            _populateEmailAgentImpl(agent);
+            return;
+        }
+
+        if ((userAgent != null) && userAgent.startsWith("PTG")) {
+            _populateIaswAgentImpl(userAgent, headerMap
+                    .get(_IASW_DEVICE_HINT_PARAM), agent);
+            return;
+        }
+
+        String accept = headerMap.get("Accept");
+
+        // See if the agent wants WML - if so, we're talking WAP.
+        if ((accept != null)
+                && accept.regionMatches(true, 0, "vnd.wap.wml", 0, 11)) {
+            _populateWAPAgentImpl(agent);
+            return;
+        }
+
+        if (userAgent == null) {
+            _populateUnknownAgentImpl(null, agent);
+            return;
+        }
+
+        // the useragent string for telnet and PDA design time will start with
+        // OracleJDevMobile because in each of these cases we know we have an
+        // exact match in the device repository for the agent name. This is
+        // because the jdev design time and ITS runtime have access to the same
+        // device repository as the Trinidad runtime
+        // The PDA DT useragent string will be: OracleJDevMobile/PDA/[agentName]
+        // The telnet DT and RT useragent string will be:
+        // OracleJDevMobile/ITS/[agentName]
+        if (userAgent.startsWith("OracleJDevMobile")) {
+            _populateJDevMobileAgentImpl(userAgent, agent);
+            return;
+        }
+        if (userAgent.startsWith("OracleITS")) {
+            _populateTelnetAgentImpl(userAgent, agent);
+            return;
+        }
+        if (userAgent.startsWith("Pixo-Browser")) {
+            _populatePixoAgentImpl(userAgent, agent);
+            return;
+        }
+
+        if (userAgent.startsWith("ICE Browser")) {
+            _populateIceAgentImpl(userAgent, agent);
+            return;
+        }
+
+        // Web Pro
+        // userAgent =
+        // "Mozilla/4.76 (compatible; MSIE 6.0; U; Windows 95; PalmSource; PalmOS; WebPro; Tungsten Proxyless 1.1 320x320x16)";
+        if ((userAgent.indexOf("WebPro") != -1 && userAgent.indexOf("Palm") != -1)
+                || userAgent.indexOf("Blazer/3.") != -1) {
+            _populatePalmWebBrowserProAgentImpl(userAgent, agent);
+            return;
+        }
+
+        /*
+           * //Commenting - Confirm this pattern fornBlazer before uncommenting
+           * //and remove the Blazer 3.0 check in the previous if if
+           * (((userAgent.indexOf("Blazer/4.") != -1) ||
+           * (userAgent.indexOf("Blazer 3.") != -1)) &&
+           * ((userAgent.indexOf("Palm") != -1))) { return
+           * _getPalmBlazerAgentEntry(userAgent); }
+           */
+
+        // PPC 02
+        // userAgent =
+        // "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PPC; 240x320)";
+        // PPC 03
+        // userAgent =
+        // "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)";
+        if (userAgent.indexOf("Windows CE") != -1) {
+            // for PocketPC and Windows Mobile, try to grab the header UA-pixels
+            // to
+            // determine width/height
+            String uaPixels = headerMap.get("UA-pixels");
+            _populatePocketPCAgentImpl(userAgent, uaPixels, agent);
+            return;
+        }
+
+        // This needs to be before check for mozilla!
+        if ((userAgent.indexOf("PalmOS") != -1)
+                || (userAgent.indexOf("Blazer") != -1)
+                || (userAgent.indexOf("Xiino") != -1)) {
+            _populatePalmAgentImpl(userAgent, agent);
+            return;
+        }
+
+        if ((userAgent.indexOf("AppleWebKit") != -1)
+                || (userAgent.indexOf("Safari") != -1)) {
+            _populateSafariAgentImpl(userAgent, agent);
+            return;
+        }
+
+        if (userAgent.startsWith("BlackBerry")) {
+            _populateBlackberryAgentImpl(userAgent, agent);
+            return;
+        }
+
+        if (userAgent.indexOf("Opera") > -1) {
+            _populateOperaAgentImpl(userAgent, agent);
+            return;
+        }
+
+        // Generic Mobile Browser Detection
+        // The user agent signature varies depending on the
+        // device manufacturer and carrier. Use case insensitive
+        // string matching.
+        // Some of the browsers listed below support higher capabilities
+        // than basic HTML browser capabilities. However, those browsers
+        // are treated as basic HTML browser here for maximam compatibility
+        // and performance.
+        // We do not support WAP1.X browsers (WML).
+
+        String userAgentLowercase = userAgent.toLowerCase();
+
+        if ((userAgentLowercase.indexOf("wap1.") < 0)
+                && (userAgentLowercase.indexOf("wap2.") > -1
+                || userAgentLowercase.indexOf("up.browser") > -1
+                || userAgentLowercase.indexOf("nokia") > -1
+                || userAgentLowercase.startsWith("mot-")
+                || userAgentLowercase.indexOf("symbian") > -1
+                || userAgentLowercase.indexOf("sonyeri") > -1
+                || userAgentLowercase.indexOf("netfront/") > -1
+                || userAgentLowercase.startsWith("samsang-")
+                || userAgentLowercase.startsWith("lg-")
+                || userAgentLowercase.indexOf("obigo") > -1
+                || userAgentLowercase.indexOf("vodafone") > -1
+                || userAgentLowercase.indexOf("kddi") > -1 || userAgentLowercase
+                .indexOf("openwave") > -1)) {
+            _populateGenericPDAAgentImpl(userAgent, agent);
+            return;
+        }
+
+        // Gecko and Mozilla tests should be placed following more specific
+        // uiser-agent test.
+        if (userAgent.indexOf("Gecko/") != -1) {
+            _populateGeckoAgentImpl(userAgent, agent);
+            return;
+        }
+        // must check for gecko before checking for mozilla:
+        else if (userAgent.startsWith("Mozilla")) {
+            _populateMozillaAgentImpl(userAgent, agent);
+            return;
+        }
+
+        _populateUnknownAgentImpl(userAgent, agent);
+    }
+
+    private void _populateGenericPDAAgentImpl(String userAgent, AgentImpl agent) {
+        // Generic PDA browser
+        agent.setType(TYPE_PDA);
+        agent.setAgent(AGENT_GENERICPDA);
+        agent.setAgentVersion("1"); // Version does not matter
+        agent.setPlatform(PLATFORM_GENERICPDA);
+    }
+
+    private void _populateUnknownAgentImpl(String userAgent, AgentImpl agent) {
+        // Log warning message that we are setting the agent entry to unknown
+        // attributes
+        // TODO: _LOG.warning("UNKNOWN_AGENT_ATTRIBUTES_CREATE_WITH_UNKNOWN",
+        // userAgent);
+        agent.setAgent(UNKNOWN);
+        agent.setType(UNKNOWN);
+        agent.setAgentVersion(UNKNOWN);
+        agent.setPlatform(UNKNOWN);
+        agent.setPlatformVersion(UNKNOWN);
+        agent.setMakeModel(UNKNOWN);
+    }
+
+    // populates the agent entry for DT access for either Telnet or PDA
+    // for jdev mobile there are two user agent strings possible:
+    // 1. OracleJDevMobile_PDA(DeviceName:[name of device])
+    // 2. OracleJDevMobile_ITS(DeviceName:[name of device])
+    private void _populateJDevMobileAgentImpl(String agent, AgentImpl agentObj) {
+        // the form of JDEVMobile user agent string will be:
+        // OracleJDevMobile_[PDA or ITS]/[version](DeviceName:[device
+        // name];[capability1]:[capability 1 value];...)
+
+        boolean returnUnknownAgentObj = false;
+        int itsIndex = agent.indexOf("ITS");
+        int pdaIndex = agent.indexOf("PDA");
+        int versionStartIndex = -1;
+        if (itsIndex > -1) {
+            agentObj.setType(TYPE_TELNET);
+            versionStartIndex = "OracleJDevMobile_ITS".length() + 1;
+        } else if (pdaIndex > -1) {
+
+            agentObj.setType(TYPE_PDA);
+            versionStartIndex = "OracleJDevMobile_PDA".length() + 1;
+        } else {
+            returnUnknownAgentObj = true;
+        }
+        // Now find the name of the device
+        if (!returnUnknownAgentObj) {
+            int versionEndIndex = agent.indexOf("(");
+            String version = agent
+                    .substring(versionStartIndex, versionEndIndex);
+            agentObj.setAgentVersion(version);
+            // parse agentName
+            int agentNameStartIndex = agent.indexOf(":", versionEndIndex) + 1;
+            // find end of agentName (ie. when we see a semicolon
+            int agentNameEndIndex = agentNameStartIndex;
+            for (; agent.charAt(agentNameEndIndex) != ';'
+                    && agent.charAt(agentNameEndIndex) != ')'; agentNameEndIndex++)
+                ;
+            String agentName = agent.substring(agentNameStartIndex,
+                    agentNameEndIndex);
+            agentObj.setAgent(agentName);
+            if (agent.charAt(agentNameEndIndex) == ')')
+                return;
+            // now parse remaining request specific capabilities
+            int capabilityNameStartIndex;
+            int capabilityNameEndIndex;
+            int capabilityValueStartIndex;
+            int capabilityValueEndIndex = agentNameEndIndex;
+            while (agent.charAt(capabilityValueEndIndex) != ')') {
+                capabilityNameStartIndex = capabilityValueEndIndex + 1;
+                capabilityNameEndIndex = agent.indexOf(":",
+                        capabilityNameStartIndex);
+                String capabilityName = agent.substring(
+                        capabilityNameStartIndex, capabilityNameEndIndex);
+                capabilityValueStartIndex = capabilityNameEndIndex + 1;
+                capabilityValueEndIndex = agent.indexOf(";",
+                        capabilityValueStartIndex);
+                if (capabilityValueEndIndex == -1) {
+                    capabilityValueEndIndex = agent.indexOf(")",
+                            capabilityValueEndIndex);
+                }
+                String capabilityValue = agent.substring(
+                        capabilityValueStartIndex, capabilityValueEndIndex);
+                agentObj.__addRequestCapability(CapabilityKey.getCapabilityKey(
+                        capabilityName, true), capabilityValue);
+            }
+        }
+        if (returnUnknownAgentObj) {
+            _populateUnknownAgentImpl(agent, agentObj);
+        }
+    }
+
+    private void _populateTelnetAgentImpl(String agent, AgentImpl agentObj) {
+        // the form of an ITS user agent will be
+        // OracleITS/[version](DeviceName:[device
+        // name];[capability1]:[capability 1 value];...)
+        agentObj.setType(TYPE_TELNET);
+        int versionStartIndex = "OracleITS".length() + 1;
+        int versionEndIndex = agent.indexOf("(");
+        String version = agent.substring(versionStartIndex, versionEndIndex);
+        agentObj.setAgentVersion(version);
+        // parse agentName
+        int agentNameStartIndex = agent.indexOf(":", versionEndIndex) + 1;
+        // find end of agentName (ie. when we see a semicolon
+        int agentNameEndIndex = agentNameStartIndex;
+        for (; agent.charAt(agentNameEndIndex) != ';'
+                && agent.charAt(agentNameEndIndex) != ')'; agentNameEndIndex++)
+            ;
+        String agentName = agent.substring(agentNameStartIndex,
+                agentNameEndIndex);
+        agentObj.setAgent(agentName);
+        if (agent.charAt(agentNameEndIndex) == ')')
+            return;
+        // now parse remaining request specific capabilities
+        int capabilityNameStartIndex;
+        int capabilityNameEndIndex;
+        int capabilityValueStartIndex;
+        int capabilityValueEndIndex = agentNameEndIndex;
+        while (agent.charAt(capabilityValueEndIndex) != ')') {
+            capabilityNameStartIndex = capabilityValueEndIndex + 1;
+            capabilityNameEndIndex = agent.indexOf(":",
+                    capabilityNameStartIndex);
+            String capabilityName = agent.substring(capabilityNameStartIndex,
+                    capabilityNameEndIndex);
+            capabilityValueStartIndex = capabilityNameEndIndex + 1;
+            capabilityValueEndIndex = agent.indexOf(";",
+                    capabilityValueStartIndex);
+            if (capabilityValueEndIndex == -1) {
+                capabilityValueEndIndex = agent.indexOf(")",
+                        capabilityValueEndIndex);
+            }
+            String capabilityValue = agent.substring(capabilityValueStartIndex,
+                    capabilityValueEndIndex);
+            agentObj.__addRequestCapability(CapabilityKey.getCapabilityKey(
+                    capabilityName, true), capabilityValue);
+        }
+    }
+
+    /**
+     * populates data from a PocketPC IE request
+     */
+    private void _populatePocketPCAgentImpl(String agent, String uaPixels,
+                                            AgentImpl agentObj) {
+        int start = agent.indexOf("MSIE");
+        String version = null;
+
+        if (start > -1) {
+            version = _getVersion(agent, start + "MSIE".length());
+        }
+        agentObj.setType(TYPE_PDA);
+        agentObj.setAgent(AGENT_IE);
+        agentObj.setAgentVersion(version);
+        agentObj.setPlatform(PLATFORM_PPC);
+
+        boolean narrowScreenDevice = false;
+
+        if (uaPixels != null && uaPixels.length() > 0) {
+            // UA-pixels is defined as <width>x<height>
+            // UA-pixels was proposed here
+            // http://www.watersprings.org/pub/id/draft-mutz-http-attributes-00.txt
+            // and it is used by Pocket IE and IE Mobile; see
+            // http://blogs.msdn.com/iemobile/archive/2006/08/03/Detecting_IE_Mobile.aspx
+            Integer width = null;
+            Integer height = null;
+
+            String[] parts = uaPixels.split("x");
+            if (parts.length == 2) {
+                try {
+                    width = new Integer(parts[0]);
+                    height = new Integer(parts[1]);
+                } catch (NumberFormatException ex) {
+                    // TODO: _LOG.fine(ex);
+                }
+            }
+
+            if (width != null && height != null) {
+                agentObj.__addRequestCapability(CapabilityConstants.CAP_WIDTH,
+                        width);
+                agentObj.__addRequestCapability(CapabilityConstants.CAP_HEIGHT,
+                        height);
+
+                if (width.intValue() < XhtmlAgentConstants.NARROW_SCREEN_PDA_MAX_WIDTH) {
+                    narrowScreenDevice = true;
+                }
+            } else {
+                // TODO:
+                // _LOG.fine("When creating the Agent, the UA-pixels value \"{0}\" could not be parsed.",
+                // uaPixels);
+            }
+        } else {
+            narrowScreenDevice = true;
+        }
+
+        if (narrowScreenDevice) {
+            agentObj.__addRequestCapability(
+                    CapabilityConstants.CAP_NARROW_SCREEN, Boolean.TRUE);
+        } else {
+            agentObj.__addRequestCapability(
+                    CapabilityConstants.CAP_NARROW_SCREEN, Boolean.FALSE);
+        }
+    }
+
+    /**
+     * populates data from a Blackberry browser request
+     */
+    private void _populateBlackberryAgentImpl(String agent, AgentImpl agentObj) {
+        // the User-Agent string for the BlackBerry Browser starts with
+        // BlackBerry<model>/<version> where <model> is the BlackBerry
+        // model, e.g. for the BlackBerry browser 4.1.0 on
+        // the BlackBerry 8700 device, the User-Agent string begins with
+        // BlackBerry8700/4.1.0
+
+        int start = agent.indexOf("BlackBerry");
+
+        String version = null;
+        String makeModel = null;
+
+        if (start > -1) {
+            // find the first /, which occurs before the version number
+            int slashLoc = agent.indexOf('/', start);
+            if (slashLoc > -1) {
+                // see the note above about how the User-Agent starts with
+                // BlackBerry<model>/<version>; this returns the
+                // BlackBerry<model> (e.g. BlackBerry8700), which we will
+                // use as the Agent hardwareMakeModel
+                makeModel = agent.substring(start, slashLoc);
+
+                // _getVersion assumes the location of the slash is passed in,
+                // and starts looking for the version at the NEXT character
+                version = _getVersion(agent, slashLoc);
+            }
+        }
+
+        // note that the agent and platform are both BLACKBERRY
+        // this is because it is the BlackBerry Browser running on the
+        // BlackBerry device
+        agentObj.setType(TYPE_PDA);
+        agentObj.setAgent(AGENT_BLACKBERRY);
+        agentObj.setAgentVersion(version);
+        agentObj.setPlatform(PLATFORM_BLACKBERRY);
+        agentObj.setMakeModel(makeModel);
+        // Most of BlackBerry devices' widths are more than 240px, so
+        // don't consider BlackBerry as a narrow-screen PDA.
+        agentObj.__addRequestCapability(CapabilityConstants.CAP_NARROW_SCREEN,
+                Boolean.FALSE);
+    }
+
+    /**
+     * returns the data for the Palm Web Pro browser request
+     */
+    private void _populatePalmWebBrowserProAgentImpl(String agent,
+                                                     AgentImpl agentObj) {
+        agentObj.setType(TYPE_PDA);
+        agentObj.setAgent(AGENT_WEBPRO);
+
+        int start = agent.indexOf("WebPro/");
+
+        if (start > -1) {
+            agentObj.setAgentVersion(_getVersion(agent, start + 6));
+        }
+
+        agentObj.setPlatform(PLATFORM_PALM);
+
+    }
+
+    /**
+     * returns the data for the Palm blazer browser request
+     */
+    /*
+      * //comment for now private AgentEntry _getPalmBlazerAgentEntry(String
+      * agent) { AgentEntry entry = new AgentEntry(); entry._type = TYPE_PDA;
+      * entry._agent = AdfFacesAgent.AGENT_BLAZER;
+      *
+      * //balzer 3 has "Blazer 3..." and 4.0 has Blazer 4/.... int start =
+      * agent.indexOf("Blazer");
+      *
+      * if (start > -1) { entry._agentVersion = _getVersion(agent, start + 6); }
+      *
+      * entry._platform = Agent.PLATFORM_PALM;
+      *
+      * return entry; }
+      */
+
+    /**
+     * returns the AgentEntry for ias wireless
+     */
+    private void _populateIaswAgentImpl(String agent, String wirelessType,
+                                        AgentImpl agentObj) {
+        // map device hint to agent type
+        if (wirelessType == null) {
+            _populateUnknownAgentImpl(agent, agentObj);
+            return;
+        }
+
+        String version = _getVersion(agent, agent.indexOf('/'));
+        agentObj.setType(TYPE_PHONE);
+        agentObj.setAgent(AGENT_PTG);
+        agentObj.setAgentVersion(version);
+    }
+
+    /**
+     * returns the AgentEntry for the Palm
+     */
+    private void _populatePalmAgentImpl(String userAgent, AgentImpl agentObj) {
+        agentObj.setType(TYPE_PDA);
+
+        if (userAgent.indexOf("Blazer") != -1)
+            agentObj.setAgent(AGENT_BLAZER);
+        else if (userAgent.indexOf("Xiino") != -1)
+            agentObj.setAgent(AGENT_XIINO);
+
+        agentObj.setPlatform(PLATFORM_PALM);
+
+    }
+
+    /**
+     * returns the AgentEntry for the Ice brwoser
+     */
+    private void _populateIceAgentImpl(String agent, AgentImpl agentObj) {
+        int slashIndex = agent.indexOf('/');
+        agentObj.setType(TYPE_DESKTOP);
+        agentObj.setAgent(AGENT_ICE_BROWSER);
+        agentObj.setAgentVersion(_getVersion(agent, slashIndex));
+        agentObj.setPlatform(_getJavaOS(agent, slashIndex));
+    }
+
+    /**
+     * returns the AgentEntry for the Pixo Microbrowser
+     */
+    private void _populatePixoAgentImpl(String agent, AgentImpl agentObj) {
+        agentObj.setType(TYPE_PHONE);
+        agentObj.setAgent(AGENT_PIXO);
+        agentObj.setAgentVersion(_getVersion(agent, agent.indexOf('/')));
+    }
+
+    /**
+     * Returns an AgentEntry for a WML client.
+     */
+    private void _populateWAPAgentImpl(AgentImpl agentObj) {
+        // TODO: Add generic wmlbrowser when wml browsers are supported
+        // Generic WML support
+        agentObj.setType(TYPE_PHONE);
+    }
+
+    /**
+     * Returns an AgentEntry for the browsers that use the Gecko Layout Engine.
+     */
+    private void _populateGeckoAgentImpl(String agent, AgentImpl agentObj) {
+        // Identifying an Gecko Based agent as Gecko (and not Mozilla, Netscape,
+        // Firefox)
+        // could be an issue
+        // E.g User-Agent String
+        // Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.1) Gecko/20020823
+        // Netscape/7.0
+        // For Gecko based agents
+        // - Gecko uses Date string as a version number
+        // - Mozilla uses the revision number as the version number rv:x.x.x
+        // - Each vendor has a version number (like firefox/1.0, Netscape/7.0)
+        // Mozilla revision : Gecko Version
+        // 1.0.1 : 20020826
+        // 1.1 : 20020826
+        // 1.2.1 : 20021130
+
+        // Currently (in UIX 2.2 base agent Impl)
+        // - All Gecko Based agents are identified as Gecko
+        // - But PPR capability is determined is based on the Mozilla version
+        // number (rv:x.x.x)
+        // - For Major version , for Gecko, always "1" is returned
+        // so stricly speaking all capabilities are not based on the layout
+        // engine.
+
+        // New Impl.
+        // - Still using Gecko as the identifier for all gecko based agents
+        // - Still returning date string as version number of Gecko. But this
+        // can get messy to use
+        // by the applications. The version number could change everyday and may
+        // not be the same for
+        // different platforms. (An alternate option is to return version number
+        // of Mozilla
+        // that would be equivalent to current browser for Gecko-based browsers)
+        // - But assumes PPR Support in all Gecko versions.
+
+        // Change 2008-05-13:
+        // We need the rv to support @agent versioning in CSS as the date makes
+        // no sense,
+        // so look for the rv:, not the Gecko build date
+
+        agentObj.setType(TYPE_DESKTOP);
+        agentObj.setAgent(AGENT_GECKO);
+
+        int start = agent.indexOf("rv:");
+        if (start >= 0) {
+            agentObj.setAgentVersion(_getVersion(agent, start + 2));
+        } else {
+            int geckoIndex = agent.indexOf("Gecko/");
+            agentObj.setAgentVersion(agent.substring(geckoIndex + 6, // skip
+                    // over
+                    // 'Gecko/'
+                    geckoIndex + 14)); // always 8 chars length
+        }
+
+        int paren = agent.indexOf('(');
+
+        if (paren >= 0) {
+            // try to determine the OS
+            if (agent.indexOf("Win", paren) > 0) {
+                agentObj.setPlatform(PLATFORM_WINDOWS);
+            } else if (agent.indexOf("Mac", paren) > 0) {
+                agentObj.setPlatform(PLATFORM_MACOS);
+            } else if (agent.indexOf("Linux", paren) > 0) {
+                agentObj.setPlatform(PLATFORM_LINUX);
+            } else if (agent.indexOf("Sun", paren) > 0) {
+                agentObj.setPlatform(PLATFORM_SOLARIS);
+            }
+        }
+    }
+
+    /**
+     * Returns an AgentEntry for the Opera browser.
+     */
+
+    private void _populateOperaAgentImpl(String agent, AgentImpl agentObj) {
+        int start = agent.indexOf("Opera Mini");
+        if (start > -1) {
+            // Opera Mini supports JavaScript. However, generic PDA capability
+            // will be assigned to maximize the compatibility until fully
+            // certified.
+            start = agent.indexOf('/', start);
+            String version = _getVersion(agent, start);
+            agentObj.setAgentVersion(version);
+            agentObj.setType(TYPE_PDA);
+            agentObj.setAgent(AGENT_GENERICPDA);
+            agentObj.setPlatform(PLATFORM_GENERICPDA);
+        }
+        // For performance reasons, consider Opera Mobile as a generic
+        // PDA-browser
+        // so just return. It will be handle by _populateGenricPDAImpl().
+        else if (agent.indexOf("MOT-") != -1 || agent.indexOf("Nokia") != -1) {
+            return;
+        } else {
+            agentObj.setType(TYPE_DESKTOP);
+            agentObj.setAgent(AGENT_GECKO);
+
+            int operaIndex = agent.indexOf("Opera/");
+            int firstSpace = agent.indexOf(" ");
+            if (operaIndex >= 0 && firstSpace >= 0) {
+                agentObj.setAgentVersion(agent.substring(operaIndex + 6,
+                        firstSpace));
+            }
+
+            int paren = agent.indexOf('(');
+
+            if (paren >= 0) {
+                // try to determine the OS
+                if (agent.indexOf("Win", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_WINDOWS);
+                } else if (agent.indexOf("Mac", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_MACOS);
+                } else if (agent.indexOf("Linux", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_LINUX);
+                } else if (agent.indexOf("Sun", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_SOLARIS);
+                }
+            }
+        }
+    }
+
+    /**
+     * returns the AgentEntry for Safari
+     */
+    private void _populateSafariAgentImpl(String agent, AgentImpl agentObj) {
+        int start = agent.indexOf("AppleWebKit");
+
+        if (start < 0) {
+            start = agent.indexOf("Safari");
+        }
+
+        if (start >= 0) {
+            start = agent.indexOf('/', start);
+        }
+
+        if (agent.indexOf("iPhone") > 0) {
+            agentObj.setPlatform(PLATFORM_IPHONE);
+        } else if (agent.indexOf("iPod") > 0) {
+            // At the moment, the iPod touch version of this browser matches
+            // iPhone's
+            agentObj.setPlatform(PLATFORM_IPHONE);
+        } else if (agent.indexOf("Win") > 0) {
+            // At the moment, this includes Safari and Google Chrome
+            agentObj.setPlatform(PLATFORM_WINDOWS);
+        } else if (agent.indexOf("Linux") > 0) {
+            // At the moment, this includes Android
+            agentObj.setPlatform(PLATFORM_LINUX);
+        } else if (agent.indexOf("Mac") > 0) {
+            // At the moment, this includes Safari
+            agentObj.setPlatform(PLATFORM_MACOS);
+        }
+
+        String version = _getVersion(agent, start);
+        agentObj.setType(TYPE_DESKTOP);
+        if ((agent.indexOf("Symbian") > -1) || (agent.indexOf("Nokia") > -1)) {
+            agentObj.setAgent(AGENT_NOKIA_S60);
+            agentObj.setPlatform(AGENT_NOKIA_S60);
+        } else {
+            agentObj.setAgent(AGENT_WEBKIT);
+        }
+        agentObj.setAgentVersion(version);
+    }
+
+    /**
+     * Returns an AgentEntry for the "Mozilla" family of browsers - which most
+     * at least pretend to be.
+     */
+    private void _populateMozillaAgentImpl(String agent, AgentImpl agentObj) {
+        int paren = agent.indexOf('(');
+        agentObj.setType(TYPE_DESKTOP); // Is this default realli okay???
+        // These days Mobile agents also
+        // use Mozilla/xx.xx
+
+        // No section to qualify the agent; assume Mozilla/Netscape
+        if (paren == -1) {
+            agentObj.setAgent(AGENT_NETSCAPE);
+            agentObj.setAgentVersion(_getVersion(agent, agent.indexOf('/')));
+        } else {
+            paren = paren + 1;
+
+            boolean isJDevVE = agent.indexOf("JDeveloper", paren) > 0;
+            boolean isJDevJSVE = agent.indexOf("JDeveloper JS", paren) > 0;
+
+            if (agent.indexOf("Konqueror", paren) >= 0) {
+                agentObj.setType(TYPE_DESKTOP);
+                agentObj.setAgent(AGENT_KONQUEROR);
+                agentObj.setAgentVersion(_getVersion(agent, agent
+                        .lastIndexOf('/')));
+            } else if (agent.startsWith("compatible", paren)) {
+                int ieIndex = agent.indexOf("MSIE", paren);
+
+                if (ieIndex < 0) {
+                    // check for Palm
+                    int palmIndex = agent.indexOf("Elaine", paren);
+
+                    if (palmIndex > 0) {
+                        agentObj.setType(TYPE_PDA);
+                        agentObj.setAgent(AGENT_ELAINE);
+                        agentObj.setAgentVersion(_getVersion(agent, palmIndex));
+                        agentObj.setPlatform(PLATFORM_PALM);
+                    }
+                } else {
+                    agentObj.setAgent(AGENT_IE);
+                    agentObj.setAgentVersion(_getVersion(agent, ieIndex + 4));
+                }
+            } else {
+                agentObj.setAgent(AGENT_NETSCAPE);
+                agentObj
+                        .setAgentVersion(_getVersion(agent, agent.indexOf('/')));
+            }
+
+            // try to determine the OS, if unknown
+            if (agentObj.getPlatformName() == null) {
+                // Hack: treat the JDeveloper agent as Windows,
+                // so that we assume IE 6.0 Windows capabilities
+                if ((agent.indexOf("Win", paren) > 0) || isJDevVE) {
+                    agentObj.setPlatform(PLATFORM_WINDOWS);
+                } else if (agent.indexOf("Mac", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_MACOS);
+                } else if (agent.indexOf("Linux", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_LINUX);
+                } else if (agent.indexOf("Sun", paren) > 0) {
+                    agentObj.setPlatform(PLATFORM_SOLARIS);
+                }
+            }
+
+            if (isJDevVE) {
+                agentObj.__addRequestCapability(
+                        CapabilityConstants.CAP_IS_JDEV_VE, Boolean.TRUE);
+                if (isJDevJSVE) {
+                    agentObj.__addRequestCapability(
+                            CapabilityConstants.CAP_IS_JDEV_JAVASCRIPT_VE,
+                            Boolean.TRUE);
+                }
+
+            }
+        }
+    }
+
+    /**
+     * Returns an AgentEntry for the email agents like Outlook 2007 and
+     * Thunderbird
+     */
+    private void _populateEmailAgentImpl(AgentImpl agentObj) {
+
+        agentObj.setType(TYPE_DESKTOP);
+
+        agentObj.setAgent(AGENT_EMAIL);
+        agentObj.setAgentVersion("0.0");
+        agentObj.setPlatform(UNKNOWN);
+        agentObj.setPlatformVersion(UNKNOWN);
+        agentObj.setMakeModel(UNKNOWN);
+
+    }
+
+    /**
+     * Returns the version contained within a string starting at a certain
+     * location. The version will contain only numeric parts separated by dots
+     * (.).
+     *
+     * @param base  the string to pull the version from
+     * @param start the index of the character BEFORE the version
+     * @return the version string
+     */
+    private String _getVersion(String base, int start) {
+        // start should be the character BEFORE the version portion
+        // (typically a slash character after the agent name)
+
+        if (start < 0) {
+            return null;
+        }
+
+        int end = base.length();
+        start = start + 1;
+
+        for (int i = start; i < end; i++) {
+            // Find the last non-numeric character; that'll
+            // mark the end of the version
+            char ch = base.charAt(i);
+
+            if ((ch != '.') && ((ch < '0') || (ch > '9'))) {
+                return base.substring(start, i);
+            }
+        }
+
+        return base.substring(start);
+    }
+
+    /**
+     * Parse the OS string returned from java.System.
+     * <p/>
+     * Currently, only checks for Windows
+     */
+    private String _getJavaOS(String base, int start) {
+        if (start < 0) {
+            return null;
+        }
+
+        // check for Windows
+        if (base.regionMatches(start, "Windows", 0, base.length() - start)) {
+            return PLATFORM_WINDOWS;
+        }
+
+        return null;
+    }
+
+    static private final String _EMAIL_PARAM = "org.apache.myfaces.trinidad.agent.email";
+    static final private String _IASW_DEVICE_HINT_PARAM = "X-Oracle-Device.Class";
+}

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/commons/trunk/myfaces-commons-agent/src/main/java/org/apache/myfaces/commons/agent/impl/AgentFactoryImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain