NetUtils.java Source code

Java tutorial

Introduction

Here is the source code for NetUtils.java

Source

/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * A collection of <code>File</code>, <code>URL</code> and filename
 * utility methods
 *
 * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
 * @version CVS $Revision: 1.1 $ $Date: 2002/03/17 13:37:13 $
 */

public class NetUtils {

    /**
     * Array containing the safe characters set as defined by RFC 1738
     */
    private static BitSet safeCharacters;

    private static final char[] hexadecimal = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
            'D', 'E', 'F' };

    static {
        safeCharacters = new BitSet(256);
        int i;
        // 'lowalpha' rule
        for (i = 'a'; i <= 'z'; i++) {
            safeCharacters.set(i);
        }
        // 'hialpha' rule
        for (i = 'A'; i <= 'Z'; i++) {
            safeCharacters.set(i);
        }
        // 'digit' rule
        for (i = '0'; i <= '9'; i++) {
            safeCharacters.set(i);
        }

        // 'safe' rule
        safeCharacters.set('$');
        safeCharacters.set('-');
        safeCharacters.set('_');
        safeCharacters.set('.');
        safeCharacters.set('+');

        // 'extra' rule
        safeCharacters.set('!');
        safeCharacters.set('*');
        safeCharacters.set('\'');
        safeCharacters.set('(');
        safeCharacters.set(')');
        safeCharacters.set(',');

        // special characters common to http: file: and ftp: URLs ('fsegment' and 'hsegment' rules)
        safeCharacters.set('/');
        safeCharacters.set(':');
        safeCharacters.set('@');
        safeCharacters.set('&');
        safeCharacters.set('=');
    }

    /**
     * Decode a path
     *
     * @param path the path to decode
     * @return the decoded path
     */
    public static String decodePath(String path) throws Exception {
        return java.net.URLDecoder.decode(path, "koi8-r");
    }

    /**
     * Encode a path as required by the URL specificatin (<a href="http://www.ietf.org/rfc/rfc1738.txt">
     * RFC 1738</a>). This differs from <code>java.net.URLEncoder.encode()</code> which encodes according
     * to the <code>x-www-form-urlencoded</code> MIME format.
     *
     * @param path the path to encode
     * @return the encoded path
     */
    public static String encodePath(String path) {
        // stolen from org.apache.catalina.servlets.DefaultServlet ;)

        /**
         * Note: This code portion is very similar to URLEncoder.encode.
         * Unfortunately, there is no way to specify to the URLEncoder which
         * characters should be encoded. Here, ' ' should be encoded as "%20"
         * and '/' shouldn't be encoded.
         */

        int maxBytesPerChar = 10;
        StringBuffer rewrittenPath = new StringBuffer(path.length());
        ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
        OutputStreamWriter writer = null;
        try {
            writer = new OutputStreamWriter(buf, "UTF8");
        } catch (Exception e) {
            e.printStackTrace();
            writer = new OutputStreamWriter(buf);
        }

        for (int i = 0; i < path.length(); i++) {
            int c = (int) path.charAt(i);
            if (safeCharacters.get(c)) {
                rewrittenPath.append((char) c);
            } else {
                // convert to external encoding before hex conversion
                try {
                    writer.write(c);
                    writer.flush();
                } catch (IOException e) {
                    buf.reset();
                    continue;
                }
                byte[] ba = buf.toByteArray();
                for (int j = 0; j < ba.length; j++) {
                    // Converting each byte in the buffer
                    byte toEncode = ba[j];
                    rewrittenPath.append('%');
                    int low = (int) (toEncode & 0x0f);
                    int high = (int) ((toEncode & 0xf0) >> 4);
                    rewrittenPath.append(hexadecimal[high]);
                    rewrittenPath.append(hexadecimal[low]);
                }
                buf.reset();
            }
        }

        return rewrittenPath.toString();
    }

    /**
     * Returns the path of the given resource.
     *
     * @path the resource
     * @return the resource path
     */
    public static String getPath(String uri) {
        int i = uri.lastIndexOf('/');
        if (i > -1)
            return uri.substring(0, i);
        i = uri.indexOf(':');
        return (i > -1) ? uri.substring(i + 1, uri.length()) : "";
    }

    /**
     * Remove path and file information from a filename returning only its
     * extension  component
     *
     * @param filename The filename
     * @return The filename extension (with starting dot!)
     */
    public static String getExtension(String uri) {
        int dot = uri.lastIndexOf('.');
        if (dot > -1) {
            uri = uri.substring(dot);
            int slash = uri.lastIndexOf('/');
            if (slash > -1) {
                return null;
            } else {
                int sharp = uri.lastIndexOf('#');
                if (sharp > -1) {
                    // uri starts with dot already
                    return uri.substring(0, sharp);
                } else {
                    int mark = uri.lastIndexOf('?');
                    if (mark > -1) {
                        // uri starts with dot already
                        return uri.substring(0, mark);
                    } else {
                        return uri;
                    }
                }
            }
        } else {
            return null;
        }
    }

    /**
     * Absolutize a relative resource on the given absolute path.
     *
     * @path the absolute path
     * @relativeResource the relative resource
     * @return the absolutized resource
     */
    public static String absolutize(String path, String relativeResource) {
        if (("".equals(path)) || (path == null))
            return relativeResource;
        if (relativeResource.charAt(0) != '/') {
            int length = path.length() - 1;
            boolean slashPresent = (path.charAt(length) == '/');
            StringBuffer b = new StringBuffer();
            b.append(path);
            if (!slashPresent)
                b.append('/');
            b.append(relativeResource);
            return b.toString();
        } else {
            // resource is already absolute
            return relativeResource;
        }
    }

    /**
     * Relativize an absolute resource on a given absolute path.
     *
     * @path the absolute path
     * @relativeResource the absolute resource
     * @return the resource relative to the given path
     */
    public static String relativize(String path, String absoluteResource) {
        if (("".equals(path)) || (path == null))
            return absoluteResource;
        int length = path.length() - 1;
        boolean slashPresent = path.charAt(length) == '/';
        if (absoluteResource.startsWith(path)) {
            // resource is direct descentant
            return absoluteResource.substring(length + (slashPresent ? 1 : 2));
        } else {
            // resource is not direct descendant
            if (!slashPresent)
                path += "/";
            int index = StringUtils.matchStrings(path, absoluteResource);
            if (index > 0 && path.charAt(index - 1) != '/') {
                index = path.substring(0, index).lastIndexOf('/');
                index++;
            }
            String pathDiff = path.substring(index);
            String resource = absoluteResource.substring(index);
            int levels = StringUtils.count(pathDiff, '/');
            StringBuffer b = new StringBuffer();
            for (int i = 0; i < levels; i++) {
                b.append("../");
            }
            b.append(resource);
            return b.toString();
        }
    }

    /**
     * Normalize a uri containing ../ and ./ paths.
     *
     * @param uri The uri path to normalize
     * @return The normalized uri
     */
    public static String normalize(String uri) {
        String[] dirty = StringUtils.split(uri, "/");
        int length = dirty.length;
        String[] clean = new String[length];

        boolean path;
        boolean finished;
        while (true) {
            path = false;
            finished = true;
            for (int i = 0, j = 0; (i < length) && (dirty[i] != null); i++) {
                if (".".equals(dirty[i])) {
                    // ignore
                } else if ("..".equals(dirty[i])) {
                    clean[j++] = dirty[i];
                    if (path)
                        finished = false;
                } else {
                    if ((i + 1 < length) && ("..".equals(dirty[i + 1]))) {
                        i++;
                    } else {
                        clean[j++] = dirty[i];
                        path = true;
                    }
                }
            }
            if (finished) {
                break;
            } else {
                dirty = clean;
                clean = new String[length];
            }
        }

        StringBuffer b = new StringBuffer(uri.length());

        for (int i = 0; (i < length) && (clean[i] != null); i++) {
            b.append(clean[i]);
            if ((i + 1 < length) && (clean[i + 1] != null))
                b.append("/");
        }

        return b.toString();
    }

    /**
     * Remove parameters from a uri.
     *
     * @param uri The uri path to deparameterize.
     * @param parameters The map that collects parameters.
     * @return The cleaned uri
     */
    public static String deparameterize(String uri, Map parameters) {
        int i = uri.lastIndexOf('?');
        if (i == -1)
            return uri;
        String[] params = StringUtils.split(uri.substring(i + 1), "&");
        for (int j = 0; j < params.length; j++) {
            String p = params[j];
            int k = p.indexOf('=');
            if (k == -1)
                break;
            String name = p.substring(0, k);
            String value = p.substring(k + 1);
            parameters.put(name, value);
        }
        return uri.substring(0, i);
    }

    public static String parameterize(String uri, Map parameters) {
        if (parameters.size() == 0) {
            return uri;
        }
        StringBuffer buffer = new StringBuffer(uri);
        buffer.append('?');
        for (Iterator i = parameters.entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Map.Entry) i.next();
            buffer.append(entry.getKey());
            buffer.append('=');
            buffer.append(entry.getValue());
            if (i.hasNext()) {
                buffer.append('&');
            }
        }
        return buffer.toString();
    }
}

/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/

/**
 * A collection of <code>String</code> handling utility methods.
 *
 * @author <a href="mailto:ricardo@apache.org">Ricardo Rocha</a>
 * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
 * @version CVS $Revision: 1.1 $ $Date: 2002/03/17 13:37:13 $
 */
class StringUtils {

    /**
     * Split a string as an array using whitespace as separator
     *
     * @param line The string to be split
     * @return An array of whitespace-separated tokens
     */
    public static String[] split(String line) {
        return split(line, " \t\n\r");
    }

    /**
     * Split a string as an array using a given set of separators
     *
     * @param line The string to be split
     * @param delimiter A string containing token separators
     * @return An array of token
     */
    public static String[] split(String line, String delimiter) {
        return Tokenizer.tokenize(line, delimiter, false);
    }

    /**
     * Tests whether a given character is alphabetic, numeric or
     * underscore
     *
     * @param c The character to be tested
     * @return whether the given character is alphameric or not
     */
    public static boolean isAlphaNumeric(char c) {
        return c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
    }

    /**
     * Counts the occurrence of the given char in the string.
     *
     * @param str The string to be tested
     * @param c the char to be counted
     * @return the occurrence of the character in the string.
     */
    public static int count(String str, char c) {
        int index = 0;
        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == c)
                index++;
        }
        return index;
    }

    /**
     * Matches two strings.
     *
     * @param a The first string
     * @param b The second string
     * @return the index where the two strings stop matching starting from 0
     */
    public static int matchStrings(String a, String b) {
        int i;
        char[] ca = a.toCharArray();
        char[] cb = b.toCharArray();
        int len = (ca.length < cb.length) ? ca.length : cb.length;

        for (i = 0; i < len; i++) {
            if (ca[i] != cb[i])
                break;
        }

        return i;
    }

    /**
     * Replaces tokens in input with Value present in System.getProperty
     */
    public static String replaceToken(String s) {
        int startToken = s.indexOf("${");
        int endToken = s.indexOf("}", startToken);
        String token = s.substring(startToken + 2, endToken);
        StringBuffer value = new StringBuffer();
        value.append(s.substring(0, startToken));
        value.append(System.getProperty(token));
        value.append(s.substring(endToken + 1));
        return value.toString();
    }
}

/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/

/**
 * Replacement for StringTokenizer in java.util, beacuse of bug in the
 * Sun's implementation.
 *
 * @author <A HREF="mailto:moravek@pobox.sk">Peter Moravek</A>
 */
class Tokenizer implements Enumeration {

    /**
     * Constructs a string tokenizer for the specified string. All characters
     * in the delim argument are the delimiters for separating tokens.
     * If the returnTokens flag is true, then the delimiter characters are
     * also returned as tokens. Each delimiter is returned as a string of
     * length one. If the flag is false, the delimiter characters are skipped
     * and only serve as separators between tokens.
     *
     * @param str           a string to be parsed
     * @param delim         the delimiters
     * @param returnTokens  flag indicating whether to return the delimiters
     *                      as tokens
     */
    public Tokenizer(String str, String delim, boolean returnTokens) {
        this.str = str;
        this.delim = delim;
        this.returnTokens = returnTokens;

        max = str.length();
    }

    /**
     * Constructs a string tokenizer for the specified string. The characters
     * in the delim argument are the delimiters for separating tokens.
     * Delimiter characters themselves will not be treated as tokens.
     *
     * @param str          a string to be parsed
     * @param delim        the delimiters
     */
    public Tokenizer(String str, String delim) {
        this(str, delim, false);
    }

    /**
     * Constructs a string tokenizer for the specified string. The character
     * in the delim argument is the delimiter for separating tokens.
     * Delimiter character themselves will not be treated as token.
     *
     * @param str          a string to be parsed
     * @param delim        the delimiter
     */
    public Tokenizer(String str, char delim) {
        this(str, String.valueOf(delim), false);
    }

    /**
     * Constructs a string tokenizer for the specified string. The tokenizer
     * uses the default delimiter set, which is " \t\n\r\f": the space
     * character, the tab character, the newline character, the carriage-return
     * character, and the form-feed character. Delimiter characters themselves
     * will not be treated as tokens.
     *
     * @param str          a string to be parsed
     */
    public Tokenizer(String str) {
        this(str, DEFAULT_DELIMITERS, false);
    }

    /**
     * Tests if there are more tokens available from this tokenizer's string.
     * If this method returns true, then a subsequent call to nextToken with
     * no argument will successfully return a token.
     *
     * @return true if and only if there is at least one token in the string
     * after the current position; false otherwise.
     */
    public boolean hasMoreTokens() {
        return ((current < max) ? (true)
                : (((current == max) && (max == 0 || (returnTokens && delim.indexOf(str.charAt(previous)) >= 0)))));
    }

    /**
     * Returns the next token from this string tokenizer.
     *
     * @return the next token from this string tokenizer
     *
     * @exception NoSuchElementException  if there are no more tokens in this
     *                                    tokenizer's string
     */
    public String nextToken() throws NoSuchElementException {
        if (current == max && (max == 0 || (returnTokens && delim.indexOf(str.charAt(previous)) >= 0))) {

            current++;
            return new String();
        }

        if (current >= max)
            throw new NoSuchElementException();

        int start = current;
        String result = null;

        if (delim.indexOf(str.charAt(start)) >= 0) {
            if (previous == -1
                    || (returnTokens && previous != current && delim.indexOf(str.charAt(previous)) >= 0)) {

                result = new String();
            } else if (returnTokens)
                result = str.substring(start, ++current);

            if (!returnTokens)
                current++;
        }

        previous = start;
        start = current;

        if (result == null)
            while (current < max && delim.indexOf(str.charAt(current)) < 0)
                current++;

        return result == null ? str.substring(start, current) : result;
    }

    /**
     * Returns the next token in this string tokenizer's string. First, the
     * set of characters considered to be delimiters by this Tokenizer
     * object is changed to be the characters in the string delim.
     * Then the next token in the string after the current position is
     * returned. The current position is advanced beyond the recognized token.
     * The new delimiter set remains the default after this call.
     *
     * @param delim the new delimiters
     *
     * @return the next token, after switching to the new delimiter set
     *
     * @exception NoSuchElementException  if there are no more tokens in this
     *                                    tokenizer's string.
     */
    public String nextToken(String delim) throws NoSuchElementException {
        this.delim = delim;
        return nextToken();
    }

    /**
     * Returns the same value as the hasMoreTokens method. It exists so that
     * this class can implement the Enumeration interface.
     *
     * @return true if there are more tokens; false otherwise.
     */
    public boolean hasMoreElements() {
        return hasMoreTokens();
    }

    /**
     * Returns the same value as the nextToken method, except that its
     * declared return value is Object rather than String. It exists so that
     * this class can implement the Enumeration interface.
     *
     * @return the next token in the string
     *
     * @exception NoSuchElementException  if there are no more tokens in this
     *                                    tokenizer's string
     */
    public Object nextElement() {
        return nextToken();
    }

    /**
     * Calculates the number of times that this tokenizer's nextToken method
     * can be called before it generates an exception. The current position
     * is not advanced.
     *
     * @return  the number of tokens remaining in the string using the
     *          current delimiter set
     */
    public int countTokens() {
        int curr = current;
        int count = 0;

        for (int i = curr; i < max; i++) {
            if (delim.indexOf(str.charAt(i)) >= 0)
                count++;

            curr++;
        }

        return count + (returnTokens ? count : 0) + 1;
    }

    /**
     * Resets this tokenizer's state so the tokenizing starts from the begin.
     */
    public void reset() {
        previous = -1;
        current = 0;
    }

    /**
     * Constructs a string tokenizer for the specified string. All characters
     * in the delim argument are the delimiters for separating tokens.
     * If the returnTokens flag is true, then the delimiter characters are
     * also returned as tokens. Each delimiter is returned as a string of
     * length one. If the flag is false, the delimiter characters are skipped
     * and only serve as separators between tokens. Then tokenizes the str
     * and return an String[] array with tokens.
     *
     * @param str           a string to be parsed
     * @param delim         the delimiters
     * @param returnTokens  flag indicating whether to return the delimiters
     *                      as tokens
     *
     * @return array with tokens
     */
    public static String[] tokenize(String str, String delim, boolean returnTokens) {

        Tokenizer tokenizer = new Tokenizer(str, delim, returnTokens);
        String[] tokens = new String[tokenizer.countTokens()];

        int i = 0;
        while (tokenizer.hasMoreTokens()) {
            tokens[i] = tokenizer.nextToken();
            i++;
        }

        return tokens;
    }

    /**
     * Default delimiters "\t\n\r\f":
     * the space character, the tab character, the newline character,
     * the carriage-return character, and the form-feed character.
     */
    public static final String DEFAULT_DELIMITERS = " \t\n\r\f";

    /**
     * String to tokenize.
     */
    private String str = null;

    /**
     * Delimiters.
     */
    private String delim = null;

    /**
     * Flag indicating whether to return the delimiters as tokens.
     */
    private boolean returnTokens = false;

    /**
     * Previous token start.
     */
    private int previous = -1;

    /**
     * Current position in str string.
     */
    private int current = 0;

    /**
     * Maximal position in str string.
     */
    private int max = 0;
}