ParseURL.java Source code

Java tutorial

Introduction

Here is the source code for ParseURL.java

Source

/*
Copyright 2007 Creare Inc.
    
Licensed 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 com.rbnb.utility;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Hashtable;

/******************************************************************************
 * Parse a URL into its components.
 * <p>
 * Components in the URL include:
 * 
 *
 * @author John P. Wilson
 *
 * @version 09/28/2006
 */

/*
 * Copyright 2006 Creare Inc.
 * All Rights Reserved
 *
 *   Date      By       Description
 * MM/DD/YYYY
 * ----------  --       -----------
 * 09/28/2006  JPW   RBNB servlet no longer supports special meaning for the
 *         "msg" munge.  Therefore, I have removed "msg" as an
 *         RBNB munge.  As part of this, I removed the method
 *         getCompleteMessageMunge() and the "message" member
 *         variable.
 * 09/15/2006  JPW      Switch over to using KeyValueHash to parse the munge
 * 05/10/2006  JPW      Created
 *
 */

public class ParseURL {

    // A copy of the original, full URL
    private String url;

    // Request protocol, such as "http" or "ftp"
    private String protocol = null;

    // The request string, stripped of any protocol and munge options
    private String request = null;

    // The original, complete munge string
    private String munge = null;

    // RBNB munge options
    private boolean hasRBNBMunge = false; //EMF 5/12/06
    private Double time = null;
    private Double duration = null;
    private String reference = null;
    private String fetch = null;
    private String byteorder = null;
    private String datatype = null;
    private Integer mux = null;
    private Integer blocksize = null;
    private String mime = null;

    // Hashtable of non-RBNB munge options
    private Hashtable nonRBNBMunge = null;

    /**************************************************************************
     * Default constructor.
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/10/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/10/2006  JPW    Created
     *
     */

    public ParseURL() {
        this(null, false);
    }

    /**************************************************************************
     * Constructor.  Call parse() to parse the given URL into its components.
     * <p>
     *
     * @author John P. Wilson
     *
     * @param urlStrI      The URL to parse.
     * @param bDebugI      Print debug?
     *
     * @version 05/10/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/10/2006  JPW    Created
     *
     */

    public ParseURL(String urlStrI, boolean bDebugI) {
        parse(urlStrI, bDebugI);
    }

    /**************************************************************************
     * Parse the given URL into its components.
     * <p>
     * This method parses a munged URL such as:
     *
     *     http://jpw.creare.com:80/RBNB/TestSource?r=newest&t=1.5
     *
     * In this case:
     *     "http" is the protocol
     *     "jpw.creare.com:80/RBNB/TestSource" is the request
     *     "newest" is the reference
     *     "1.5" is the time
     *
     * @author John P. Wilson
     *
     * @param urlStrI      The URL to parse.
     * @param bDebugI      Print debug?
     *
     * @version 09/15/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 09/15/2006  JPW    Switch over to using KeyValueHash to parse the munge
     * 05/10/2006  JPW    Created
     *
     */

    public void parse(String urlStrI, boolean bDebugI) {

        // Reset all member variables
        resetMemberData();

        if ((urlStrI == null) || (urlStrI.trim().equals(""))) {
            if (bDebugI) {
                System.err.println("Unable to parse URL: empty string");
            }
            return;
        }

        url = new String(urlStrI);

        if (bDebugI) {
            System.err.println("URL = \"" + urlStrI + "\"");
        }

        ////////////////////////////////////////////
        // See if a protocol is specified in the URL
        ////////////////////////////////////////////
        int colonIndex = urlStrI.indexOf(':');
        String requestAndMungeStr = urlStrI;
        if (colonIndex >= 0) {
            protocol = urlStrI.substring(0, colonIndex);
            if ((protocol != null) && (protocol.trim().equals(""))) {
                protocol = null;
            }
            if ((protocol != null) && (bDebugI)) {
                System.err.println("Protocol = \"" + protocol + "\"");
            } else if (bDebugI) {
                System.err.println("Protocol = null");
            }
            requestAndMungeStr = urlStrI.substring(colonIndex + 1);
        }

        ////////////////////////////////////////////////
        // Strip off leading '/' from requestAndMungeStr
        ////////////////////////////////////////////////
        while ((requestAndMungeStr != null) && (!requestAndMungeStr.equals(""))
                && (requestAndMungeStr.charAt(0) == '/')) {
            requestAndMungeStr = requestAndMungeStr.substring(1);
        }

        ///////////////////////////////////////////////////////////
        // Separate the request from the munge; munge portion could
        // begin with either '?' or '@'
        ///////////////////////////////////////////////////////////
        request = null;
        munge = null;
        int mungeStartCharIndex = requestAndMungeStr.indexOf('@');
        if (mungeStartCharIndex < 0) {
            mungeStartCharIndex = requestAndMungeStr.indexOf('?');
        }
        if (mungeStartCharIndex >= 0) {
            request = requestAndMungeStr.substring(0, mungeStartCharIndex);
            if ((request != null) && (request.trim().equals(""))) {
                request = null;
            }
            munge = requestAndMungeStr.substring(mungeStartCharIndex + 1);
            if ((munge != null) && (munge.trim().equals(""))) {
                munge = null;
            }
        } else { //EMF 5/11/06: no munge, all request
            request = requestAndMungeStr;
            munge = null;
        }
        if (bDebugI) {
            if (request == null) {
                System.err.println("Request = null");
            } else {
                System.err.println("Request = \"" + request + "\"");
            }
            if (munge == null) {
                System.err.println("Munge = null");
            } else {
                System.err.println("Munge = \"" + munge + "\"");
            }
        }

        //////////////////////////
        // Parse the munge options
        //////////////////////////
        if (munge == null) {
            // We're all done
            return;
        }
        // JPW 09/15/2006: Use KeyValueHash to parse the munge
        char[] terminatorChars = { '&' };
        KeyValueHash kvh = new KeyValueHash(munge, terminatorChars);
        Hashtable fullHashtable = kvh.getHash();
        if (kvh.get("time") != null) {
            // Store time as a Double object
            try {
                time = new Double(kvh.get("time"));
                if (bDebugI) {
                    System.err.println("time = " + time);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                time = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("time");
        }
        if (kvh.get("t") != null) {
            // Store time as a Double object
            try {
                time = new Double(kvh.get("t"));
                if (bDebugI) {
                    System.err.println("time = " + time);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                time = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("t");
        }
        if (kvh.get("duration") != null) {
            // Store duration as a Double object
            try {
                duration = new Double(kvh.get("duration"));
                if (bDebugI) {
                    System.err.println("duration = " + duration);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                duration = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("duration");
        }
        if (kvh.get("d") != null) {
            // Store duration as a Double object
            try {
                duration = new Double(kvh.get("d"));
                if (bDebugI) {
                    System.err.println("duration = " + duration);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                duration = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("d");
        }
        if (kvh.get("reference") != null) {
            reference = kvh.get("reference");
            if (bDebugI) {
                System.err.println("reference = " + reference);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("reference");
        }
        if (kvh.get("r") != null) {
            reference = kvh.get("r");
            if (bDebugI) {
                System.err.println("reference = " + reference);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("r");
        }
        if (kvh.get("fetch") != null) {
            fetch = kvh.get("fetch");
            if (bDebugI) {
                System.err.println("fetch = " + fetch);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("fetch");
        }
        if (kvh.get("f") != null) {
            fetch = kvh.get("f");
            if (bDebugI) {
                System.err.println("fetch = " + fetch);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("f");
        }
        if (kvh.get("byteorder") != null) {
            byteorder = kvh.get("byteorder");
            if (bDebugI) {
                System.err.println("byteorder = " + byteorder);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("byteorder");
        }
        if (kvh.get("bo") != null) {
            byteorder = kvh.get("bo");
            if (bDebugI) {
                System.err.println("byteorder = " + byteorder);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("bo");
        }
        if (kvh.get("datatype") != null) {
            datatype = kvh.get("datatype");
            if (bDebugI) {
                System.err.println("datatype = " + datatype);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("datatype");
        }
        if (kvh.get("dt") != null) {
            datatype = kvh.get("dt");
            if (bDebugI) {
                System.err.println("datatype = " + datatype);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("dt");
        }
        if (kvh.get("mux") != null) {
            // Store mux as an Integer object
            try {
                mux = new Integer(kvh.get("mux"));
                if (bDebugI) {
                    System.err.println("mux = " + mux);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                mux = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("mux");
        }
        if (kvh.get("x") != null) {
            // Store mux as an Integer object
            try {
                mux = new Integer(kvh.get("x"));
                if (bDebugI) {
                    System.err.println("mux = " + mux);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                mux = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("x");
        }
        if (kvh.get("blocksize") != null) {
            // Store blocksize as an Integer object
            try {
                blocksize = new Integer(kvh.get("blocksize"));
                if (bDebugI) {
                    System.err.println("blocksize = " + blocksize);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                blocksize = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("blocksize");
        }
        if (kvh.get("bs") != null) {
            // Store blocksize as an Integer object
            try {
                blocksize = new Integer(kvh.get("bs"));
                if (bDebugI) {
                    System.err.println("blocksize = " + blocksize);
                }
                hasRBNBMunge = true;
            } catch (NumberFormatException e) {
                // Nothing to do
                blocksize = null;
            }
            // Remove this entry from the hashtable
            fullHashtable.remove("bs");
        }
        if (kvh.get("mime") != null) {
            mime = kvh.get("mime");
            if (bDebugI) {
                System.err.println("mime = " + mime);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("mime");
        }
        if (kvh.get("m") != null) {
            mime = kvh.get("m");
            if (bDebugI) {
                System.err.println("mime = " + mime);
            }
            hasRBNBMunge = true;
            // Remove this entry from the hashtable
            fullHashtable.remove("m");
        }

        // What remains in fullHashtable must be the non-RBNB munges
        if ((fullHashtable != null) && (!fullHashtable.isEmpty())) {
            nonRBNBMunge = fullHashtable;
            if (bDebugI) {
                for (Enumeration e = nonRBNBMunge.keys(); e.hasMoreElements();) {
                    String key = (String) e.nextElement();
                    String value = (String) nonRBNBMunge.get(key);
                    System.err.println("Non-RBNB munge: key = \"" + key + "\", value = \"" + value + "\"");
                }
            }
        }

    }

    /**************************************************************************
     * Reset member data to default values.
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/10/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/10/2006  JPW    Created
     *
     */

    public void resetMemberData() {
        url = null;
        protocol = null;
        request = null;
        munge = null;
        time = null;
        duration = null;
        reference = null;
        fetch = null;
        byteorder = null;
        datatype = null;
        mux = null;
        blocksize = null;
        mime = null;
        nonRBNBMunge = null;
    }

    /**************************************************************************
     * Get the original URL as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getURL() {
        return url;
    }

    /**************************************************************************
     * Get URL protocol as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getProtocol() {
        return protocol;
    }

    /**************************************************************************
     * Get URL request as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getRequest() {
        return request;
    }

    /**************************************************************************
     * Get the URL munge as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getMunge() {
        return munge;
    }

    /**************************************************************************
    * Indicates whether any RBNB munge exists
    * <p>
    *
    * @author Eric M. Friets
    *
    * @version 05/12/2006
    */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/12/2006  EMF    Created
     *
     */

    public boolean isRBNBMunge() {
        return hasRBNBMunge;
    }

    /**************************************************************************
     * Get time munge option as a Double object
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public Double getTime() {
        return time;
    }

    /**************************************************************************
     * Get duration munge option as a Double object
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public Double getDuration() {
        return duration;
    }

    /**************************************************************************
     * Set a new duration for the munge.
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 06/02/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 06/02/2006  JPW    Created
     *
     */

    public void setDuration(double durationI) {
        if (durationI >= 0.0) {
            duration = new Double(durationI);
        }
    }

    /**************************************************************************
     * Get reference munge option as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getReference() {
        return reference;
    }

    /**************************************************************************
     * Get fetch munge option as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getFetch() {
        return fetch;
    }

    /**************************************************************************
     * Get byteorder munge option as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getByteorder() {
        return byteorder;
    }

    /**************************************************************************
     * Get datatype munge option as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getDatatype() {
        return datatype;
    }

    /**************************************************************************
     * Get mux munge option as an Integer object
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public Integer getMux() {
        return mux;
    }

    /**************************************************************************
     * Get blocksize munge option as an Integer object
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public Integer getBlocksize() {
        return blocksize;
    }

    /**************************************************************************
     * Get mime munge option as a String
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getMime() {
        return mime;
    }

    /**************************************************************************
     * Get Hashtable nonRBNBMunge
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public Hashtable getNonRBNBMunge() {
        return nonRBNBMunge;
    }

    /**************************************************************************
     * Get all non-RBNB munge options concatenated together, using '&' as
     * the separator character.
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 05/11/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 05/11/2006  JPW    Created
     *
     */

    public String getNonRBNBMungeStr() {
        if (nonRBNBMunge == null) {
            return null;
        }
        StringBuffer mungeStrBuf = null;
        for (Enumeration e = nonRBNBMunge.keys(); e.hasMoreElements();) {
            String nextKey = (String) e.nextElement();
            String nextValue = (String) nonRBNBMunge.get(nextKey);
            if (mungeStrBuf == null) {
                mungeStrBuf = new StringBuffer(nextKey + "=" + nextValue);
            } else {
                mungeStrBuf.append("&" + nextKey + "=" + nextValue);
            }
        }
        return mungeStrBuf.toString();
    }

    /**************************************************************************
     * Default version of this method; include all munge components.
     * <p>
     *
     * @author John P. Wilson
     *
     * @version 06/02/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 06/02/2006  JPW    Created
     *
     */

    public String createNewRBNBMunge() {
        return createNewRBNBMunge(false, false, false, false, false, false, false, false, false, false);
    }

    /**************************************************************************
     * Create a new munge string containing the desired RBNB munge components.
     * <p>
     * The user can selectively remove munge components as specified by the
     * boolean arguments.  If the user has not chosen to remove any munge
     * component, then the original, complete munge string is returned.
     *
     * @author John P. Wilson
     *
     * @param bRemoveTimeI      Remove time from returned munge?
     * @param bRemoveDurationI      Remove duration from returned munge?
     * @param bRemoveReferenceI      Remove reference from returned munge?
     * @param bRemoveFetchI      Remove fetch from returned munge?
     * @param bRemoveByteorderI      Remove byteorder from returned munge?
     * @param bRemoveDatatypeI      Remove datatype from returned munge?
     * @param bRemoveMuxI      Remove mux from returned munge?
     * @param bRemoveBlocksizeI      Remove blocksize from returned munge?
     * @param bRemoveMimeI      Remove mime from returned munge?
     * @param bRemoveNonRBNBMungeI   Remove non RBNB munges from returned munge?
     *
     * @version 09/28/2006
     */

    /*
     *
     *   Date      By     Description
     * MM/DD/YYYY
     * ----------  --     -----------
     * 09/28/2006  JPW    Change "bRemoveMessageI" to "bRemoveNonRBNBMungeI"
     * 06/02/2006  JPW    Created
     *
     */

    public String createNewRBNBMunge(boolean bRemoveTimeI, boolean bRemoveDurationI, boolean bRemoveReferenceI,
            boolean bRemoveFetchI, boolean bRemoveByteorderI, boolean bRemoveDatatypeI, boolean bRemoveMuxI,
            boolean bRemoveBlocksizeI, boolean bRemoveMimeI, boolean bRemoveNonRBNBMungeI) {

        // JPW 09/28/2006: If user has not chosen to remove anything, then
        //                 simply return the original, complete munge string.
        if ((!bRemoveTimeI) && (!bRemoveDurationI) && (!bRemoveReferenceI) && (!bRemoveFetchI)
                && (!bRemoveByteorderI) && (!bRemoveDatatypeI) && (!bRemoveMuxI) && (!bRemoveBlocksizeI)
                && (!bRemoveMimeI) && (!bRemoveNonRBNBMungeI)) {
            return munge;
        }

        StringBuffer newMunge = new StringBuffer();

        if ((getTime() != null) && (!bRemoveTimeI)) {
            newMunge.append("&t=" + getTime().toString());
        }
        if ((getDuration() != null) && (!bRemoveDurationI)) {
            newMunge.append("&d=" + getDuration().toString());
        }
        if ((getReference() != null) && (!bRemoveReferenceI)) {
            newMunge.append("&r=" + getReference());
        }
        if ((getFetch() != null) && (!bRemoveFetchI)) {
            newMunge.append("&f=" + getFetch());
        }
        if ((getByteorder() != null) && (!bRemoveByteorderI)) {
            newMunge.append("&bo=" + getByteorder());
        }
        if ((getDatatype() != null) && (!bRemoveDatatypeI)) {
            newMunge.append("&dt=" + getDatatype());
        }
        if ((getMux() != null) && (!bRemoveMuxI)) {
            newMunge.append("&x=" + getMux().toString());
        }
        if ((getBlocksize() != null) && (!bRemoveBlocksizeI)) {
            newMunge.append("&bs=" + getBlocksize().toString());
        }
        if ((getMime() != null) && (!bRemoveMimeI)) {
            newMunge.append("&m=" + getMime());
        }
        // JPW 09/28/2006: Return the non RBNB munges as a series of key/value
        //                 pairs; don't return them encoded in the "msg"
        //                 munge (RBNB servlet doesn't do anything special
        //                 with the "msg" munge now).
        if ((getNonRBNBMungeStr() != null) && (!bRemoveNonRBNBMungeI)) {
            newMunge.append("&" + getNonRBNBMungeStr());
        }

        if (newMunge.length() == 0) {
            return null;
        }

        // If there is a leading '&', remove it
        if (newMunge.charAt(0) == '&') {
            newMunge = newMunge.deleteCharAt(0);
        }

        return newMunge.toString();

    }

}

class KeyValueHash {
    Hashtable hash = new Hashtable();

    public KeyValueHash(byte[] userData) {

        // JPW 09/15/2006: These aren't used
        //ByteArrayInputStream byteArray = new ByteArrayInputStream(userData);
        //DataInputStream inStream = new DataInputStream(byteArray);

        // JPW 09/15/2006: Add new constructor
        this(new String(userData), null);
    }

    public KeyValueHash(String inString) {
        this(inString, null);
    }

    // JPW 09/15/2006: Add new constructor that takes a String and an optional
    //                 set of terminating characters
    public KeyValueHash(String inString, char[] terminatorCharsI) {

        // The default terminating characters
        char[] terminatorChars = { ',', '\n', '\r' };
        if ((terminatorCharsI != null) && (terminatorCharsI.length > 0)) {
            terminatorChars = terminatorCharsI;
        }

        int lt = -1; // location of the terminator from the previous iteration
        int nt = nextTerminator(inString, lt, terminatorChars);
        while (nt != -1) {
            int ne = inString.indexOf('=', lt + 1); // next equals sign
            if (ne > lt + 1 && ne < nt - 1) { //have key,value isolated
                hash.put(inString.substring(lt + 1, ne), inString.substring(ne + 1, nt));
                //System.out.println(inString.substring(lt+1,ne)+"  "+inString.substring(ne+1,nt));
            }
            lt = nt;
            while ((nt = nextTerminator(inString, lt, terminatorChars)) == lt + 1) //ignore multiple adjacent separators
                lt = nt;
        }
    } //end KeyValueHash constructor

    public String get(String key) {
        // JPW 09/15/2006: Add some checks for null
        if (key == null) {
            return null;
        }
        Object value = hash.get(key);
        if (value == null) {
            return null;
        }
        return (String) value;
    }

    public Hashtable getHash() {
        return hash;
    }

    private int nextTerminator(String s, int n, char[] t) {

        // JPW 09/15/2006: The terminator characters are provided as a parameter
        // char[] t = {',','\n','\r'}; //terminator characters

        int min = -1;
        boolean foundOne = false;

        if (n >= s.length())
            return -1; //at end of string

        for (int i = 0; i < t.length; i++) {
            int j = s.indexOf(t[i], n + 1);
            if (j >= 0) {
                if (foundOne) {
                    if (j < min)
                        min = j;
                } else {
                    foundOne = true;
                    min = j;
                }
            }
        }
        if (foundOne)
            return min;
        else
            return s.length();
    }

} //end class KeyValueHash