001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: ClientDetectionDefaultImpl.java,v 1.5 2008/06/25 05:41:32 qcheng Exp $
026 *
027 */
028
029package com.iplanet.services.cdm;
030
031import com.iplanet.am.util.AMClientDetector;
032import com.sun.identity.shared.debug.Debug;
033import java.util.Iterator;
034import javax.servlet.http.HttpServletRequest;
035
036/**
037 * The <code>ClientDetectionInterface</code> interface needs to be implemented
038 * by services and applications serving multiple clients, to determine the
039 * client from which the request has originated. This interface detects the
040 * client type from the client request.
041 * @supported.all.api
042 */
043public class ClientDetectionDefaultImpl implements ClientDetectionInterface {
044
045    protected static Debug debug = Debug.getInstance("amClientDetection");
046
047    protected static DefaultClientTypesManager defCTM = 
048        (DefaultClientTypesManager) 
049            AMClientDetector.getClientTypesManagerInstance();
050
051    /**
052     * Creates a client detection default implementation instance.
053     */
054    public ClientDetectionDefaultImpl() {
055    }
056
057    /**
058     * This is the method used by the interface to set the client-type.
059     * <code>ClientDetectionDefaultImpl</code> currently uses the following
060     * algorithm.
061     * 
062     * <pre>
063     *  if userAgent equals a known user-agent then
064     *     compare userAgent length and store the longest match
065     *  if clientType not found 
066     *     return the default clientType
067     * </pre>
068     * 
069     * @param request
070     *            The calling object passes in the
071     *            <code>HTTPServletRequest</code>.
072     * @return The string corresponding to the client type.
073     * @throws ClientDetectionException
074     *             if a default client type cannot be found
075     */
076
077    public String getClientType(HttpServletRequest request)
078            throws ClientDetectionException {
079
080        String httpUA = request.getHeader("user-agent");
081        String clientType = null;
082        int prevClientUALen = 0;
083
084        if (debug.messageEnabled()) {
085            debug.message("UserAgent : httpUA is : " + httpUA);
086            debug.message("Looking in UA/PartialMatch Maps");
087        }
088
089        Client clientInstance = null;
090        if ((clientInstance = defCTM.getFromUserAgentMap(httpUA)) != null) {
091            //
092            // Perf: We wont have to iterate thro' all clients
093            //
094            clientType = clientInstance.getClientType();
095            if (debug.messageEnabled()) {
096                debug.message("Perf: from UA Map: " + clientType);
097            }
098            return clientType;
099        } else 
100            if ((clientType = defCTM.getPartiallyMatchedClient(httpUA)) != null)
101
102        {
103            if (debug.messageEnabled()) {
104                debug.message("Perf: from PartialMatch Map: " + clientType);
105            }
106            return clientType;
107        }
108
109        // Iterate through Clients, find and save the longest match
110        int i = 0;
111        Iterator knownClients = ClientsManager.getAllInstances();
112        while (knownClients.hasNext()) {
113            clientInstance = (Client) knownClients.next();
114            i++;
115
116            String curClientUA = clientInstance.getProperty("userAgent");
117            if (curClientUA != null) {
118
119                if (debug.messageEnabled()) {
120                    debug.message("(" + i + ") Client user-agent = "
121                            + curClientUA + " :: clientType = "
122                            + clientInstance.getClientType());
123                }
124
125                if (userAgentCheck(httpUA, curClientUA)) {
126
127                    // We have a match
128                    String curClientType = clientInstance
129                            .getProperty("clientType");
130
131                    // Check length
132                    int curClientUALen = curClientUA.length();
133                    if (curClientUALen > prevClientUALen) {
134                        clientType = curClientType;
135                        prevClientUALen = curClientUALen;
136
137                        if (debug.messageEnabled()) {
138                            debug.message("Longest user-agent match client " +
139                                    "type = " + clientType);
140                        }
141                    }
142                }
143            }
144        }
145
146        // If we don't have a single match, get the default clientType
147        if (clientType == null) {
148            clientType = Client.getDefaultInstance().getProperty("clientType");
149
150            if (debug.messageEnabled()) {
151                debug.message("Default client type = " + clientType);
152            }
153        } else {
154            //
155            // Found a partial map - add it so our Map,
156            // so our next search is faster
157            //
158            defCTM.addToPartialMatchMap(httpUA, clientType);
159        }
160
161        // If we can't get the default clientType
162        if (clientType == null) {
163
164            debug.message("Unable to obtain default client type");
165
166            throw new ClientDetectionException(CDMBundle
167                    .getString("null_clientType"));
168        }
169
170        if (debug.messageEnabled()) {
171            debug.message("Returning client type : " + clientType);
172        }
173        return clientType;
174    }
175
176    /**
177     * This method contains the algorithm used to compare the 
178     * <CODE>HTTPServletRequest</CODE>
179     * user-agent versus the <CODE>Client</CODE> user-agent.
180     * 
181     * @param httpUA
182     *            The HTTPServletRequest user-agent
183     * @param clientUA
184     *            The Client userAgent
185     * @return True or false if they match
186     */
187    protected boolean userAgentCheck(String httpUA, String clientUA) {
188        if ((httpUA == null) || (clientUA == null)) {
189            return false;
190        }
191
192        if ((httpUA.equalsIgnoreCase(clientUA))
193                || (httpUA.indexOf(clientUA) > -1)) {
194            return true;
195        } else {
196            return false;
197        }
198    }
199}