FileDocCategorySizeDatePackage
I18NParseUtil.javaAPI DocGlassfish v2 API17424Fri May 04 22:36:10 BST 2007com.sun.enterprise.web.util

I18NParseUtil

public final class I18NParseUtil extends Object
Copyright 2000-2001 by iPlanet/Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. All rights reserved.

Fields Summary
public static final Logger
_logger
The logger to use for logging info about the charset found from hidden field or locale-charset-map
private static boolean
_debugLog
This indicates whether debug logging is on or not
Constructors Summary
Methods Summary
private static byteconvertHexDigit(byte b)
Convert a byte character value to hexidecimal digit value.

param
b the character value byte

        if ((b >= '0") && (b <= '9")) return (byte)(b - '0");
        if ((b >= 'a") && (b <= 'f")) return (byte)(b - 'a" + 10);
        if ((b >= 'A") && (b <= 'F")) return (byte)(b - 'A" + 10);
        return 0;
    
public static java.lang.StringgetLocaleCharsetEncoding(javax.servlet.http.HttpServletRequest request, com.sun.enterprise.deployment.runtime.web.LocaleCharsetMap[] charsetMap)
Return the charset corresponding to a (locale, agent) pair.

IMPLEMENTATION NOTE: The lcMap parameter contains an array of LocaleCharsetMap object. A LocaleCharsetMap object consist of (locale, agent, charset). The agent attribute may be a null value. If agent is null, we match the locale attribute to the requst locale. If agent is not null we match (locale, agent) to the request locale, and request agent header value. We look for exact match of the agent, so it is the user responsibility to give and exact value of the agent in ias-web XML file. If no match is found, ISO-8859-1 is returned.

param
request The request object for which a matching charset is looked for
param
lcMap an object representing locale-charset-map in sun-web.xml file
return
matching encoding or ISO-8859-1 if no match is found

        if (charsetMap == null)
            return null;

        String requestLocale = request.getLocale().toString();
        if (requestLocale == null)
            return null;

        String userAgent = request.getHeader("user-agent");

        for (int i = 0; i < charsetMap.length; i++) {
            LocaleCharsetMap element = charsetMap[i];
            String s = (String)element.getAttributeValue("Locale");
            if (s.equals(requestLocale)) {
                String agent = (String)element.getAttributeValue("Agent");
                if (agent == null || agent.length() == 0 ||
                    userAgent == null || agent.equals(userAgent)) {
                    String encoding =
                               (String)element.getAttributeValue("Charset");
                    if (_debugLog)
                        _logger.fine("Got charset in locale-charset-map" +
                                     ", locale=" + requestLocale +
                                     ", agent=" + agent +
                                     ", charset=" + encoding);
                    return encoding;
                }
            }
        }
        return null;
    
public static java.lang.StringparseParametersUsingLCInfo(java.util.Map map, java.lang.String queryString, byte[] buf, com.sun.enterprise.deployment.runtime.web.LocaleCharsetMap[] lcMap, java.lang.String hiddenFieldName, javax.servlet.http.HttpServletRequest request)
Parse the request parameter according to the locale-charset-info tag in ias-web.xml

IMPLEMENTATION NOTE: If hiddenFieldName is null, get the encoding from lcMap object, and let the original RequestUtil.parseParameters deal with the parsing. If hiddenFieldName is not null, first prase queryString to get hidden field value. if hidden field value is found in the queryString, then buf parsing will be handled by RequestUtil.parseParameters according to that value. If hidden field value is not found in queryString, then save the query string keys in a linked list and look for a hidden field value in buf. Once the hidden field value is found in buf, process the linked list of queryString according to that value. If hidden field value not found in buf either, get encoding value from lcMap. If none is found, then default to ISO-8859-1. Then process both linked list objects. NOTE: byte array buf is modified by this method. Caller beware.

param
map Map that accumulates the resulting parameters
param
queryString Input string containing request parameters
param
buf Input byte array containing request parameters
param
lcMap Inputcontainig locale-charset mapping info
param
hiddenFieldName hidden field which will specify the decoding charset
param
request object used to get the locale and agent header value
return
The encoding of the request
exception
UnsupportedEncodingException if the data is malformed


                                                                                                                                                                                                                                             
        
                               
                              
                           
          

        byte[] queryStringBytes = null;
        if ((queryString != null) && (queryString.length() > 0))
            queryStringBytes = queryString.getBytes();

        //process query string
        LinkedList queryStringKeys = new LinkedList();
        String hiddenFieldValue = processBufferWithHiddenField(
                                      map, queryStringBytes, hiddenFieldName,
                                      queryStringKeys, null, null);
        //done with query String, process buf
        //test if hidden field was found in query string
        if (hiddenFieldValue != null) {
            if (_debugLog)
                _logger.fine("Got charset from queryString, hidden field " +
                    "name = " + hiddenFieldName + ", hidden field value = " +
                    hiddenFieldValue);
            RequestUtil.parseParameters(map, buf, hiddenFieldValue);
            return hiddenFieldValue;
        }
        
        // hidden field not found in query string, try to find it in POST data
        LinkedList bufKeys = new LinkedList();
        hiddenFieldValue = processBufferWithHiddenField(
                               map, buf, hiddenFieldName, bufKeys,
                               queryStringBytes, queryStringKeys);

        if (hiddenFieldValue != null) {
            if (_debugLog)
                _logger.fine("Got charset from POST data, hidden field " +
                    "name = " + hiddenFieldName + ", hidden field value = " +
                    hiddenFieldValue);
            return hiddenFieldValue;
        }

        String encoding = null;
        if (lcMap != null) {
            encoding = getLocaleCharsetEncoding(request, lcMap);
            hiddenFieldValue = encoding;
        }

        if (encoding == null) {
            encoding = "ISO-8859-1";
            if (_debugLog)
                _logger.fine("Using default encoding to parse params: " +
                             encoding);
        }
     
        processLinkedList(map, queryStringBytes, queryStringKeys, encoding);
        processLinkedList(map, buf, bufKeys, encoding);

        return hiddenFieldValue;
    
public static java.lang.StringprocessBufferWithHiddenField(java.util.Map map, byte[] buf, java.lang.String hiddenFieldName, java.util.LinkedList keys, byte[] queryStringBytes, java.util.LinkedList queryStringKeys)
Append request parameters from the specified String to the specified Map. It is presumed that the specified Map is not accessed from any other thread, so no synchronization is performed.

IMPLEMENTATION NOTE: We look for a hidden field value in order to do URL decoding according it. While looking for that hidden field, keys are stored in a linked list along with the start and end pos of the correspondign value. This is done to avoid double parsing. Once the hidden field is found, the linked list is processed and parsing continues according to the already found hidden field value Parsing is done individually on name and value elements, rather than on the entire query string ahead of time, to properly deal with the case where the name or value includes an encoded "=" or "&" character that would otherwise be interpreted as a delimiter. NOTE: byte array data is modified by this method. Caller beware.

param
map Map that accumulates the resulting parameters
param
hiddenFieldName hidden field which will specify the decoding charset
param
keys linked list to store the keys
return
The hidden field value corresponding to hiddenFieldName
exception
UnsupportedEncodingException if the data is malformed


        int    pos = 0;
        int    ix = 0;
        int    ox = 0;
        String key = null;
        String value = null;
        boolean foundHiddenField = false;
        String hiddenFieldValue = null;

        if (buf == null)
            return null;

        while (ix < buf.length) {      
            byte c = buf[ix++];
            switch ((char) c) {
            case '&":
                if (key != null) {
                    if (foundHiddenField) {
                        value = new String(buf, pos, ox - pos,
                                           hiddenFieldValue);
                        putMapEntry(map, key, value);
                    }
                    else if (key.equals(hiddenFieldName)) {
                        hiddenFieldValue = new String(buf, pos, ox - pos,
                                                      "ISO-8859-1");
                        // hidden field found, process the linked lists that
                        // have been created so far
                        if (queryStringKeys != null)
                            processLinkedList(map, queryStringBytes,
                                         queryStringKeys, hiddenFieldValue);
                        processLinkedList(map, buf, keys, hiddenFieldValue);
                        putMapEntry(map, key, hiddenFieldValue);
                        foundHiddenField = true;
                    }
                    else {
                        Object[] startEndPos = new Object[3];
                        startEndPos[0] = key;
                        startEndPos[1] = new Integer(pos);
                        startEndPos[2] = new Integer(ox);
                        keys.add(startEndPos);
                    }
                    key = null;
                }
                pos = ix;
                ox = ix;
                break;
            case '=":
                if (key == null) {
                    key = new String(buf, pos, ox - pos, "ISO-8859-1");
                    ox = ix;
                    pos = ix;
                } else {
                    buf[ox++] = c;
                }
                break;
            case '+":
                buf[ox++] = (byte)' ";
                break;
            case '%":
                buf[ox++] = (byte)((convertHexDigit(buf[ix++]) << 4) +
                                    convertHexDigit(buf[ix++]));
                break;
            default:
                buf[ox++] = c;
            }
        }

        //The last value does not end in '&'.  So save it now.
        if (key != null) {
            if (foundHiddenField) {
                value = new String(buf, pos, ox - pos, hiddenFieldValue);
                putMapEntry(map, key, value);
            }
            else if (key.equals(hiddenFieldName)) {
                hiddenFieldValue = new String(buf, pos, ox - pos, "ISO-8859-1");
                // hidden field found, process the linked lists that
                // have been created so far
                if (queryStringKeys != null)
                    processLinkedList(map, queryStringBytes, queryStringKeys,
                                      hiddenFieldValue);
                processLinkedList(map, buf, keys, hiddenFieldValue);
                putMapEntry(map, key, hiddenFieldValue);
                foundHiddenField = true;
            }
            else {
                Object[] startEndPos = new Object[3];
                startEndPos[0] = key;
                startEndPos[1] = new Integer(pos);
                startEndPos[2] = new Integer(ox);
                keys.add(startEndPos);
            }
        }

        return hiddenFieldValue;
    
public static voidprocessLinkedList(java.util.Map map, byte[] buf, java.util.LinkedList keys, java.lang.String encoding)
Process a linked list containing. The linked list nodes consist of (key, start pos, end pos) start pos and end pos correspond to the start and end postion of the value corresponding to the key.

IMPLEMENTATION NOTE: Process the whole linked. A key, value pair is created from each node and stored in the map.

param
map Map that accumulates the resulting parameters
param
buf array of bytes to be precessed
param
keys linked listcontaning the keys
param
encoding charset for converting bytes to java strings
exception
UnsupportedEncodingException if the data is malformed


        if (buf == null || keys == null)
            return;

        ListIterator keysIterator = keys.listIterator(0);
        while (keysIterator.hasNext()) {
            Object[] startEndPos = (Object[])keysIterator.next();
            String key = (String)startEndPos[0];
            int startPos = ((Integer)startEndPos[1]).intValue();
            int endPos = ((Integer)startEndPos[2]).intValue();
            String value = new String(buf, startPos, endPos - startPos,
                                      encoding);
            putMapEntry(map, key, value);
        }
        keys.clear();
    
private static voidputMapEntry(java.util.Map map, java.lang.String name, java.lang.String value)
Put name value pair in map.

param
b the character value byte Put name and value pair in map. When name already exist, add value to array of values.

        String[] newValues = null;
        String[] oldValues = (String[]) map.get(name);
        if (oldValues == null) {
            newValues = new String[1];
            newValues[0] = value;
        } else {
            newValues = new String[oldValues.length + 1];
            System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
            newValues[oldValues.length] = value;
        }
        map.put(name, newValues);