FileDocCategorySizeDatePackage
Parameters.javaAPI DocGlassfish v2 API22317Fri May 04 22:33:14 BST 2007org.apache.tomcat.util.http

Parameters

public final class Parameters extends org.apache.tomcat.util.collections.MultiMap
author
Costin Manolache

Fields Summary
private static com.sun.org.apache.commons.logging.Log
log
private LinkedHashMap
paramHashStringArray
private boolean
didQueryParameters
private boolean
didMerge
org.apache.tomcat.util.buf.MessageBytes
queryMB
MimeHeaders
headers
org.apache.tomcat.util.buf.UDecoder
urlDec
org.apache.tomcat.util.buf.MessageBytes
decodedQuery
public static final int
INITIAL_SIZE
private Parameters
child
private Parameters
parent
private Parameters
currentChild
String
encoding
String
queryStringEncoding
org.apache.tomcat.util.buf.ByteChunk
tmpName
org.apache.tomcat.util.buf.ByteChunk
tmpValue
org.apache.tomcat.util.buf.CharChunk
tmpNameC
org.apache.tomcat.util.buf.CharChunk
tmpValueC
private static int
debug
Constructors Summary
public Parameters()

    
          
      
	super( INITIAL_SIZE );
    
Methods Summary
private voidaddParam(java.lang.String key, java.lang.String value)

	if( key==null ) return;
	String values[];
	if (paramHashStringArray.containsKey(key)) {
	    String oldValues[] = (String[])paramHashStringArray.
		get(key);
	    values = new String[oldValues.length + 1];
	    for (int i = 0; i < oldValues.length; i++) {
		values[i] = oldValues[i];
	    }
	    values[oldValues.length] = value;
	} else {
	    values = new String[1];
	    values[0] = value;
	}
	
	
	paramHashStringArray.put(key, values);
    
public voidaddParameterValues(java.lang.String key, java.lang.String[] newValues)

        if ( key==null ) return;
        String values[];
        if (paramHashStringArray.containsKey(key)) {
            String oldValues[] = (String[])paramHashStringArray.get(key);
            values = new String[oldValues.length + newValues.length];
            for (int i = 0; i < oldValues.length; i++) {
                values[i] = oldValues[i];
            }
            for (int i = 0; i < newValues.length; i++) {
                values[i+ oldValues.length] = newValues[i];
            }
        } else {
            values = newValues;
        }

        paramHashStringArray.put(key, values);
    
public org.apache.tomcat.util.http.ParametersgetCurrentSet()

	if( currentChild==null )
	    return this;
	return currentChild;
    
public java.lang.StringgetParameter(java.lang.String name)

        String[] values = getParameterValues(name);
        if (values != null) {
	    if( values.length==0 ) return "";
            return values[0];
        } else {
            return null;
        }
    
public java.util.EnumerationgetParameterNames()

	handleQueryParameters();
	// Slow - the original code
	if( currentChild!=null ) {
	    currentChild.merge();
            /* START PWC 6057385
            return currentChild.paramHashStringArray.keys();
            */
            // START PWC 6057385
            return Collections.enumeration(
                currentChild.paramHashStringArray.keySet());
            // END PWC 6057385
	}

	// merge in child
        /* START PWC 6057385
        return paramHashStringArray.keys();
        */
        // START PWC 6057385
        return Collections.enumeration(paramHashStringArray.keySet());
        // END PWC 6057385
    
public java.lang.String[]getParameterValues(java.lang.String name)

	handleQueryParameters();
	// sub-request
	if( currentChild!=null ) {
	    currentChild.merge();
	    return (String[])currentChild.paramHashStringArray.get(name);
	}

	// no "facade"
	String values[]=(String[])paramHashStringArray.get(name);
	return values;
    
public java.lang.StringgetUndecodedParameter(java.lang.String name)
Return undecoded params.

        processParameters(name);
                
	if( currentChild!=null ) {
	    currentChild.merge();
	    return (String)currentChild.paramHashStringArray.get(name);
	}

	// no "facade"
	String values[]=(String[])paramHashStringArray.get(name);
        
        if (values != null) {
	    if( values.length==0 ) return "";
            return values[0];
        } else {
	    return null;
        }
    
public voidhandleQueryParameters()
Process the query string into parameters

	if( didQueryParameters ) return;

	didQueryParameters=true;

	if( queryMB==null || queryMB.isNull() )
	    return;
	
	if( debug > 0  )
	    log( "Decoding query " + decodedQuery + " " + queryStringEncoding);

        try {
            decodedQuery.duplicate( queryMB );
        } catch (IOException e) {
            // Can't happen, as decodedQuery can't overflow
            e.printStackTrace();
        }
        processParameters( decodedQuery, queryStringEncoding );
    
private voidlog(java.lang.String s)

         
        if (log.isDebugEnabled())
	    log.debug("Parameters: " + s );
    
private voidmerge()
Combine the parameters from parent with our local ones

	// recursive
	if( debug > 0 ) {
	    log("Before merging " + this + " " + parent + " " + didMerge );
	    log(  paramsAsString());
	}
	// Local parameters first - they take precedence as in spec.
	handleQueryParameters();

	// we already merged with the parent
	if( didMerge ) return;

	// we are the top level
	if( parent==null ) return;

	// Add the parent props to the child ( lower precedence )
	parent.merge();
        /* START PWC 6057385
        Hashtable parentProps=parent.paramHashStringArray;
        */
        // START PWC 6057385
	LinkedHashMap parentProps=parent.paramHashStringArray;
        // END PWC 6057385
	merge2( paramHashStringArray , parentProps);
	didMerge=true;
	if(debug > 0 )
	    log("After " + paramsAsString());
    
private static voidmerge2(java.util.LinkedHashMap one, java.util.LinkedHashMap two)
Combine 2 hashtables into a new one. ( two will be added to one ). Used to combine child parameters ( RequestDispatcher's query ) with parent parameters ( original query or parent dispatcher )

        Iterator<String> e = two.keySet().iterator();

        while (e.hasNext()) {
            String name = e.next();
    // END PWC 6057385
	    String[] oneValue = (String[]) one.get(name);
	    String[] twoValue = (String[]) two.get(name);
	    String[] combinedValue;

	    if (twoValue == null) {
		continue;
	    } else {
		if( oneValue==null ) {
		    combinedValue = new String[twoValue.length];
		    System.arraycopy(twoValue, 0, combinedValue,
				     0, twoValue.length);
		} else {
		    combinedValue = new String[oneValue.length +
					       twoValue.length];
		    System.arraycopy(oneValue, 0, combinedValue, 0,
				     oneValue.length);
		    System.arraycopy(twoValue, 0, combinedValue,
				     oneValue.length, twoValue.length);
		}
		one.put(name, combinedValue);
	    }
	}
    
public java.lang.StringparamsAsString()
Debug purpose

	StringBuffer sb=new StringBuffer();
        /* START PWC 6057385
        Enumeration en= paramHashStringArray.keys();
        while( en.hasMoreElements() ) {
            String k=(String)en.nextElement();
        */
        // START PWC 6057385
        Iterator<String> en = paramHashStringArray.keySet().iterator();
        while( en.hasNext() ) {
            String k = en.next();
        // END PWC 6057385
	    sb.append( k ).append("=");
	    String v[]=(String[])paramHashStringArray.get( k );
	    for( int i=0; i<v.length; i++ )
		sb.append( v[i] ).append(",");
	    sb.append("\n");
	}
	return sb.toString();
    
public voidpop()
Discard the last child. This happens when we return from a sub-request and the parameters are locally modified.

	if( currentChild==null ) {
	    throw new RuntimeException( "Attempt to pop without a push" );
	}
	currentChild.recycle();
	currentChild=currentChild.parent;
	// don't remove the top.
    
public voidprocessParameters(byte[] bytes, int start, int len)

    
              
        processParameters(bytes, start, len, encoding);
    
public voidprocessParameters(byte[] bytes, int start, int len, java.lang.String enc)

	int end=start+len;
	int pos=start;
	
	if( debug>0 ) 
	    log( "Bytes: " + new String( bytes, start, len ));

        do {
	    boolean noEq=false;
	    int valStart=-1;
	    int valEnd=-1;
	    
	    int nameStart=pos;
	    int nameEnd=ByteChunk.indexOf(bytes, nameStart, end, '=" );
	    // Workaround for a&b&c encoding
	    int nameEnd2=ByteChunk.indexOf(bytes, nameStart, end, '&" );
	    if( (nameEnd2!=-1 ) &&
		( nameEnd==-1 || nameEnd > nameEnd2) ) {
		nameEnd=nameEnd2;
		noEq=true;
		valStart=nameEnd;
		valEnd=nameEnd;
		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(bytes, nameStart, nameEnd-nameStart) );
	    }
	    if( nameEnd== -1 ) 
		nameEnd=end;

	    if( ! noEq ) {
		valStart= (nameEnd < end) ? nameEnd+1 : end;
		valEnd=ByteChunk.indexOf(bytes, valStart, end, '&");
		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
	    }
	    
	    pos=valEnd+1;
	    
	    if( nameEnd<=nameStart ) {
		continue;
		// invalid chunk - it's better to ignore
		// XXX log it ?
	    }
	    tmpName.setBytes( bytes, nameStart, nameEnd-nameStart );
	    tmpValue.setBytes( bytes, valStart, valEnd-valStart );

            try {
                addParam( urlDecode(tmpName, enc), urlDecode(tmpValue, enc) );
            } catch (IOException e) {
                // Exception during character decoding: skip parameter
            }

	    tmpName.recycle();
	    tmpValue.recycle();

	} while( pos<end );
    
public voidprocessParameters(char[] chars, int start, int len)

	int end=start+len;
	int pos=start;
	
	if( debug>0 ) 
	    log( "Chars: " + new String( chars, start, len ));
        do {
	    boolean noEq=false;
	    int nameStart=pos;
	    int valStart=-1;
	    int valEnd=-1;
	    
	    int nameEnd=CharChunk.indexOf(chars, nameStart, end, '=" );
	    int nameEnd2=CharChunk.indexOf(chars, nameStart, end, '&" );
	    if( (nameEnd2!=-1 ) &&
		( nameEnd==-1 || nameEnd > nameEnd2) ) {
		nameEnd=nameEnd2;
		noEq=true;
		valStart=nameEnd;
		valEnd=nameEnd;
		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(chars, nameStart, nameEnd-nameStart) );
	    }
	    if( nameEnd== -1 ) nameEnd=end;
	    
	    if( ! noEq ) {
		valStart= (nameEnd < end) ? nameEnd+1 : end;
		valEnd=CharChunk.indexOf(chars, valStart, end, '&");
		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
	    }
	    
	    pos=valEnd+1;
	    
	    if( nameEnd<=nameStart ) {
		continue;
		// invalid chunk - no name, it's better to ignore
		// XXX log it ?
	    }
	    
	    try {
		tmpNameC.append( chars, nameStart, nameEnd-nameStart );
		tmpValueC.append( chars, valStart, valEnd-valStart );

		if( debug > 0 )
		    log( tmpNameC + "= " + tmpValueC);

		if( urlDec==null ) {
		    urlDec=new UDecoder();   
		}

		urlDec.convert( tmpNameC );
		urlDec.convert( tmpValueC );

		if( debug > 0 )
		    log( tmpNameC + "= " + tmpValueC);
		
		addParam( tmpNameC.toString(), tmpValueC.toString() );
	    } catch( IOException ex ) {
		ex.printStackTrace();
	    }

	    tmpNameC.recycle();
	    tmpValueC.recycle();

	} while( pos<end );
    
public voidprocessParameters(org.apache.tomcat.util.buf.MessageBytes data)

        processParameters(data, encoding);
    
public voidprocessParameters(org.apache.tomcat.util.buf.MessageBytes data, java.lang.String encoding)

	if( data==null || data.isNull() || data.getLength() <= 0 ) return;

	if( data.getType() == MessageBytes.T_BYTES ) {
	    ByteChunk bc=data.getByteChunk();
	    processParameters( bc.getBytes(), bc.getOffset(),
			       bc.getLength(), encoding);
	} else {
	    if (data.getType()!= MessageBytes.T_CHARS ) 
		data.toChars();
	    CharChunk cc=data.getCharChunk();
	    processParameters( cc.getChars(), cc.getOffset(),
			       cc.getLength());
	}
    
public voidprocessParameters(java.lang.String str)

	int end=str.length();
	int pos=0;
	if( debug > 0)
	    log("String: " + str );
	
        do {
	    boolean noEq=false;
	    int valStart=-1;
	    int valEnd=-1;
	    
	    int nameStart=pos;
	    int nameEnd=str.indexOf('=", nameStart );
	    int nameEnd2=str.indexOf('&", nameStart );
	    if( nameEnd2== -1 ) nameEnd2=end;
	    if( (nameEnd2!=-1 ) &&
		( nameEnd==-1 || nameEnd > nameEnd2) ) {
		nameEnd=nameEnd2;
		noEq=true;
		valStart=nameEnd;
		valEnd=nameEnd;
		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStart, nameEnd) );
	    }

	    if( nameEnd== -1 ) nameEnd=end;

	    if( ! noEq ) {
		valStart=nameEnd+1;
		valEnd=str.indexOf('&", valStart);
		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
	    }
	    
	    pos=valEnd+1;
	    
	    if( nameEnd<=nameStart ) {
		continue;
	    }
	    if( debug>0)
		log( "XXX " + nameStart + " " + nameEnd + " "
		     + valStart + " " + valEnd );
	    
	    try {
		tmpNameC.append(str, nameStart, nameEnd-nameStart );
		tmpValueC.append(str, valStart, valEnd-valStart );
	    
		if( debug > 0 )
		    log( tmpNameC + "= " + tmpValueC);

		if( urlDec==null ) {
		    urlDec=new UDecoder();   
		}

		urlDec.convert( tmpNameC );
		urlDec.convert( tmpValueC );

		if( debug > 0 )
		    log( tmpNameC + "= " + tmpValueC);
		
		addParam( tmpNameC.toString(), tmpValueC.toString() );
	    } catch( IOException ex ) {
		ex.printStackTrace();
	    }

	    tmpNameC.recycle();
	    tmpValueC.recycle();

	} while( pos<end );
    
public voidprocessSingleParameters(java.lang.String str)
Used by RequestDispatcher

	int end=str.length();
	int pos=0;
	if( debug > 0)
	    log("String: " + str );
	
        do {
	    boolean noEq=false;
	    int valStart=-1;
	    int valEnd=-1;
	    
	    int nameStart=pos;
	    int nameEnd=str.indexOf('=", nameStart );
	    int nameEnd2=str.indexOf('&", nameStart );
	    if( nameEnd2== -1 ) nameEnd2=end;
	    if( (nameEnd2!=-1 ) &&
		( nameEnd==-1 || nameEnd > nameEnd2) ) {
		nameEnd=nameEnd2;
		noEq=true;
		valStart=nameEnd;
		valEnd=nameEnd;
		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStart, nameEnd) );
	    }

	    if( nameEnd== -1 ) nameEnd=end;

	    if( ! noEq ) {
		valStart=nameEnd+1;
		valEnd=str.indexOf('&", valStart);
		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
	    }
	    
	    pos=valEnd+1;
	    
	    if( nameEnd<=nameStart ) {
		continue;
	    }
	    if( debug>0)
		log( "XXX " + nameStart + " " + nameEnd + " "
		     + valStart + " " + valEnd );
	    
	    try {
		tmpNameC.append(str, nameStart, nameEnd-nameStart );
		tmpValueC.append(str, valStart, valEnd-valStart );
	    
		if( debug > 0 )
		    log( tmpNameC + "= " + tmpValueC);

		if( urlDec==null ) {
		    urlDec=new UDecoder();   
		}

		urlDec.convert( tmpNameC );
		urlDec.convert( tmpValueC );

		if( debug > 0 )
		    log( tmpNameC + "= " + tmpValueC);
		
                if (str.compareTo(tmpNameC.toString()) == 0)
                    addParam( tmpNameC.toString(), tmpValueC.toString() );
	    } catch( IOException ex ) {
		ex.printStackTrace();
	    }

	    tmpNameC.recycle();
	    tmpValueC.recycle();

	} while( pos<end );
    
public voidpush()
Create ( or reuse ) a child that will be used during a sub-request. All future changes ( setting query string, adding parameters ) will affect the child ( the parent request is never changed ). Both setters and getters will return the data from the deepest child, merged with data from parents.

	// We maintain a linked list, that will grow to the size of the
	// longest include chain.
	// The list has 2 points of interest:
	// - request.parameters() is the original request and head,
	// - request.parameters().currentChild() is the current set.
	// The ->child and parent<- links are preserved ( currentChild is not
	// the last in the list )
	
	// create a new element in the linked list
	// note that we reuse the child, if any - pop will not
	// set child to null !
	if( currentChild==null ) {
	    currentChild=new Parameters();
	    currentChild.setURLDecoder( urlDec );
	    currentChild.parent=this;
	    return;
	}
	if( currentChild.child==null ) {
	    currentChild.child=new Parameters();
	    currentChild.setURLDecoder( urlDec );
	    currentChild.child.parent=currentChild;
	} // it is not null if this object already had a child
	// i.e. a deeper include() ( we keep it )

	// the head will be the new element.
	currentChild=currentChild.child;
	currentChild.setEncoding( encoding );
    
public voidrecycle()

	super.recycle();
	paramHashStringArray.clear();
	didQueryParameters=false;
	currentChild=null;
	didMerge=false;
	encoding=null;
	decodedQuery.recycle();
    
public voidsetEncoding(java.lang.String s)

	encoding=s;
	if(debug>0) log( "Set encoding to " + s );
    
public voidsetHeaders(MimeHeaders headers)

	this.headers=headers;
    
public voidsetQuery(org.apache.tomcat.util.buf.MessageBytes queryMB)

	this.queryMB=queryMB;
    
public voidsetQueryStringEncoding(java.lang.String s)

	queryStringEncoding=s;
	if(debug>0) log( "Set query string encoding to " + s );
    
public voidsetURLDecoder(org.apache.tomcat.util.buf.UDecoder u)

	urlDec=u;
    
private java.lang.StringurlDecode(org.apache.tomcat.util.buf.ByteChunk bc, java.lang.String enc)

        if( urlDec==null ) {
            urlDec=new UDecoder();   
        }
        urlDec.convert(bc);
        String result = null;
        if (enc != null) {
            bc.setEncoding(enc);
            result = bc.toString();
        } else {
            CharChunk cc = tmpNameC;
            int length = bc.getLength();
            cc.allocate(length, -1);
            // Default encoding: fast conversion
            byte[] bbuf = bc.getBuffer();
            char[] cbuf = cc.getBuffer();
            int start = bc.getStart();
            for (int i = 0; i < length; i++) {
                cbuf[i] = (char) (bbuf[i + start] & 0xff);
            }
            cc.setChars(cbuf, 0, length);
            result = cc.toString();
            cc.recycle();
        }
        
        return result;