alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Struts example source code file (PropertiesReader.java)

This example Struts source code file (PropertiesReader.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Struts tags/keywords

hex_radix, io, ioexception, ioexception, list, propertiesreader, runtimeexception, string, string, stringbuffer, stringbuffer, stringbuilder, stringbuilder, unable, unicode_len, util

The Struts PropertiesReader.java source code

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.opensymphony.xwork2.util;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * This class is used to read properties lines. These lines do
 * not terminate with new-line chars but rather when there is no
 * backslash sign a the end of the line.  This is used to
 * concatenate multiple lines for readability.
 * 
 * This class was pulled out of Jakarta Commons Configuration and
 * Jakarta Commons Lang trunk revision 476093
 */
public class PropertiesReader extends LineNumberReader
{
    /** Stores the comment lines for the currently processed property.*/
    private List<String> commentLines;

    /** Stores the name of the last read property.*/
    private String propertyName;

    /** Stores the value of the last read property.*/
    private String propertyValue;

    /** Stores the list delimiter character.*/
    private char delimiter;
    
    /** Constant for the supported comment characters.*/
    static final String COMMENT_CHARS = "#!";
    
    /** Constant for the radix of hex numbers.*/
    private static final int HEX_RADIX = 16;

    /** Constant for the length of a unicode literal.*/
    private static final int UNICODE_LEN = 4;
    
    /** The list of possible key/value separators */
    private static final char[] SEPARATORS = new char[] {'=', ':'};

    /** The white space characters used as key/value separators. */
    private static final char[] WHITE_SPACE = new char[]{' ', '\t', '\f'};

    /**
     * Constructor.
     *
     * @param reader A Reader.
     */
    public PropertiesReader(Reader reader)
    {
        this(reader, ',');
    }

    /**
     * Creates a new instance of <code>PropertiesReader and sets
     * the underlaying reader and the list delimiter.
     *
     * @param reader the reader
     * @param listDelimiter the list delimiter character
     * @since 1.3
     */
    public PropertiesReader(Reader reader, char listDelimiter)
    {
        super(reader);
        commentLines = new ArrayList<String>();
        delimiter = listDelimiter;
    }
    
    /**
     * Tests whether a line is a comment, i.e. whether it starts with a comment
     * character.
     *
     * @param line the line
     * @return a flag if this is a comment line
     * @since 1.3
     */
    boolean isCommentLine(String line)
    {
        String s = line.trim();
        // blanc lines are also treated as comment lines
        return s.length() < 1 || COMMENT_CHARS.indexOf(s.charAt(0)) >= 0;
    }

    /**
     * Reads a property line. Returns null if Stream is
     * at EOF. Concatenates lines ending with "\".
     * Skips lines beginning with "#" or "!" and empty lines.
     * The return value is a property definition (<code><name>
     * = <code><value>)
     *
     * @return A string containing a property value or null
     *
     * @throws IOException in case of an I/O error
     */
    public String readProperty() throws IOException
    {
        commentLines.clear();
        StringBuilder buffer = new StringBuilder();

        while (true)
        {
            String line = readLine();
            if (line == null)
            {
                // EOF
                return null;
            }

            if (isCommentLine(line))
            {
                commentLines.add(line);
                continue;
            }

            line = line.trim();

            if (checkCombineLines(line))
            {
                line = line.substring(0, line.length() - 1);
                buffer.append(line);
            }
            else
            {
                buffer.append(line);
                break;
            }
        }
        return buffer.toString();
    }

    /**
     * Parses the next property from the input stream and stores the found
     * name and value in internal fields. These fields can be obtained using
     * the provided getter methods. The return value indicates whether EOF
     * was reached (<b>false) or whether further properties are
     * available (<b>true).
     *
     * @return a flag if further properties are available
     * @throws IOException if an error occurs
     * @since 1.3
     */
    public boolean nextProperty() throws IOException
    {
        String line = readProperty();

        if (line == null)
        {
            return false; // EOF
        }

        // parse the line
        String[] property = parseProperty(line);
        propertyName = unescapeJava(property[0]);
        propertyValue = unescapeJava(property[1], delimiter);
        return true;
    }

    /**
     * Returns the comment lines that have been read for the last property.
     *
     * @return the comment lines for the last property returned by
     * <code>readProperty()
     * @since 1.3
     */
    public List<String> getCommentLines()
    {
        return commentLines;
    }

    /**
     * Returns the name of the last read property. This method can be called
     * after <code>{@link #nextProperty()} was invoked and its
     * return value was <b>true.
     *
     * @return the name of the last read property
     * @since 1.3
     */
    public String getPropertyName()
    {
        return propertyName;
    }

    /**
     * Returns the value of the last read property. This method can be
     * called after <code>{@link #nextProperty()} was invoked and
     * its return value was <b>true.
     *
     * @return the value of the last read property
     * @since 1.3
     */
    public String getPropertyValue()
    {
        return propertyValue;
    }

    /**
     * Checks if the passed in line should be combined with the following.
     * This is true, if the line ends with an odd number of backslashes.
     *
     * @param line the line
     * @return a flag if the lines should be combined
     */
    private boolean checkCombineLines(String line)
    {
        int bsCount = 0;
        for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == '\\'; idx--)
        {
            bsCount++;
        }

        return bsCount % 2 == 1;
    }

    /**
     * Parse a property line and return the key and the value in an array.
     *
     * @param line the line to parse
     * @return an array with the property's key and value
     * @since 1.2
     */
    private String[] parseProperty(String line)
    {
        // sorry for this spaghetti code, please replace it as soon as
        // possible with a regexp when the Java 1.3 requirement is dropped

        String[] result = new String[2];
        StringBuilder key = new StringBuilder();
        StringBuilder value = new StringBuilder();

        // state of the automaton:
        // 0: key parsing
        // 1: antislash found while parsing the key
        // 2: separator crossing
        // 3: value parsing
        int state = 0;

        for (int pos = 0; pos < line.length(); pos++)
        {
            char c = line.charAt(pos);

            switch (state)
            {
                case 0:
                    if (c == '\\')
                    {
                        state = 1;
                    }
                    else if (contains(WHITE_SPACE, c))
                    {
                        // switch to the separator crossing state
                        state = 2;
                    }
                    else if (contains(SEPARATORS, c))
                    {
                        // switch to the value parsing state
                        state = 3;
                    }
                    else
                    {
                        key.append(c);
                    }

                    break;

                case 1:
                    if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c))
                    {
                        // this is an escaped separator or white space
                        key.append(c);
                    }
                    else
                    {
                        // another escaped character, the '\' is preserved
                        key.append('\\');
                        key.append(c);
                    }

                    // return to the key parsing state
                    state = 0;

                    break;

                case 2:
                    if (contains(WHITE_SPACE, c))
                    {
                        // do nothing, eat all white spaces
                        state = 2;
                    }
                    else if (contains(SEPARATORS, c))
                    {
                        // switch to the value parsing state
                        state = 3;
                    }
                    else
                    {
                        // any other character indicates we encoutered the beginning of the value
                        value.append(c);

                        // switch to the value parsing state
                        state = 3;
                    }

                    break;

                case 3:
                    value.append(c);
                    break;
            }
        }

        result[0] = key.toString().trim();
        result[1] = value.toString().trim();

        return result;
    }
    
    /**
     * <p>Unescapes any Java literals found in the String to a
     * <code>Writer.

This is a slightly modified version of the * StringEscapeUtils.unescapeJava() function in commons-lang that doesn't * drop escaped separators (i.e '\,'). * * @param str the <code>String to unescape, may be null * @param delimiter the delimiter for multi-valued properties * @return the processed string * @throws IllegalArgumentException if the Writer is <code>null */ protected static String unescapeJava(String str, char delimiter) { if (str == null) { return null; } int sz = str.length(); StringBuilder out = new StringBuilder(sz); StringBuffer unicode = new StringBuffer(UNICODE_LEN); boolean hadSlash = false; boolean inUnicode = false; for (int i = 0; i < sz; i++) { char ch = str.charAt(i); if (inUnicode) { // if in unicode, then we're reading unicode // values in somehow unicode.append(ch); if (unicode.length() == UNICODE_LEN) { // unicode now contains the four hex digits // which represents our unicode character try { int value = Integer.parseInt(unicode.toString(), HEX_RADIX); out.append((char) value); unicode.setLength(0); inUnicode = false; hadSlash = false; } catch (NumberFormatException nfe) { throw new RuntimeException("Unable to parse unicode value: " + unicode, nfe); } } continue; } if (hadSlash) { // handle an escaped value hadSlash = false; if (ch == '\\') { out.append('\\'); } else if (ch == '\'') { out.append('\''); } else if (ch == '\"') { out.append('"'); } else if (ch == 'r') { out.append('\r'); } else if (ch == 'f') { out.append('\f'); } else if (ch == 't') { out.append('\t'); } else if (ch == 'n') { out.append('\n'); } else if (ch == 'b') { out.append('\b'); } else if (ch == delimiter) { out.append('\\'); out.append(delimiter); } else if (ch == 'u') { // uh-oh, we're in unicode country.... inUnicode = true; } else { out.append(ch); } continue; } else if (ch == '\\') { hadSlash = true; continue; } out.append(ch); } if (hadSlash) { // then we're in the weird case of a \ at the end of the // string, let's output it anyway. out.append('\\'); } return out.toString(); } /** * <p>Checks if the object is in the given array.

* * <p>The method returns false if a null array is passed in.

* * @param array the array to search through * @param objectToFind the object to find * @return <code>true if the array contains the object */ public boolean contains(char[] array, char objectToFind) { if (array == null) { return false; } for (char anArray : array) { if (objectToFind == anArray) { return true; } } return false; } /** * <p>Unescapes any Java literals found in the String. * For example, it will turn a sequence of <code>'\' and * <code>'n' into a newline character, unless the '\' * is preceded by another <code>'\'.

* * @param str the <code>String to unescape, may be null * @return a new unescaped <code>String, null if null string input */ public static String unescapeJava(String str) { if (str == null) { return null; } try { StringWriter writer = new StringWriter(str.length()); unescapeJava(writer, str); return writer.toString(); } catch (IOException ioe) { // this should never ever happen while writing to a StringWriter ioe.printStackTrace(); return null; } } /** * <p>Unescapes any Java literals found in the String to a * <code>Writer.

* * <p>For example, it will turn a sequence of '\' and * <code>'n' into a newline character, unless the '\' * is preceded by another <code>'\'.

* * <p>A null string input has no effect.

* * @param out the <code>Writer used to output unescaped characters * @param str the <code>String to unescape, may be null * @throws IllegalArgumentException if the Writer is <code>null * @throws IOException if error occurs on underlying Writer */ public static void unescapeJava(Writer out, String str) throws IOException { if (out == null) { throw new IllegalArgumentException("The Writer must not be null"); } if (str == null) { return; } int sz = str.length(); StringBuffer unicode = new StringBuffer(4); boolean hadSlash = false; boolean inUnicode = false; for (int i = 0; i < sz; i++) { char ch = str.charAt(i); if (inUnicode) { // if in unicode, then we're reading unicode // values in somehow unicode.append(ch); if (unicode.length() == 4) { // unicode now contains the four hex digits // which represents our unicode character try { int value = Integer.parseInt(unicode.toString(), 16); out.write((char) value); unicode.setLength(0); inUnicode = false; hadSlash = false; } catch (NumberFormatException nfe) { throw new RuntimeException("Unable to parse unicode value: " + unicode, nfe); } } continue; } if (hadSlash) { // handle an escaped value hadSlash = false; switch (ch) { case '\\': out.write('\\'); break; case '\'': out.write('\''); break; case '\"': out.write('"'); break; case 'r': out.write('\r'); break; case 'f': out.write('\f'); break; case 't': out.write('\t'); break; case 'n': out.write('\n'); break; case 'b': out.write('\b'); break; case 'u': { // uh-oh, we're in unicode country.... inUnicode = true; break; } default : out.write(ch); break; } continue; } else if (ch == '\\') { hadSlash = true; continue; } out.write(ch); } if (hadSlash) { // then we're in the weird case of a \ at the end of the // string, let's output it anyway. out.write('\\'); } } }

Other Struts examples (source code examples)

Here is a short list of links related to this Struts PropertiesReader.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.