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

Struts example source code file (WildcardHelper.java)

This example Struts source code file (WildcardHelper.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

illegalargumentexception, match_begin, match_end, match_file, match_file, match_path, match_theend, match_theend, no, no, nullpointerexception, string, string, util, wildcardhelper

The Struts WildcardHelper.java source code

/*
 * $Id: WildcardHelper.java 894087 2009-12-27 18:00:13Z martinc $
 *
 * Copyright 2003-2004 The Apache Software Foundation.
 *
 * 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.opensymphony.xwork2.util;

import java.util.Map;

/**
 * This class is an utility class that perform wilcard-patterns matching and
 * isolation taken from Apache Cocoon.
 *
 * @version $Rev: 894087 $ $Date: 2005-05-07 12:11:38 -0400 (Sat, 07 May 2005)
 *          $
 */
public class WildcardHelper implements PatternMatcher<int[]> {
    /**
     * The int representing '*' in the pattern <code>int [].
     */
    protected static final int MATCH_FILE = -1;

    /**
     * The int representing '**' in the pattern <code>int [].
     */
    protected static final int MATCH_PATH = -2;

    /**
     * The int representing begin in the pattern <code>int [].
     */
    protected static final int MATCH_BEGIN = -4;

    /**
     * The int representing end in pattern <code>int [].
     */
    protected static final int MATCH_THEEND = -5;

    /**
     * The int value that terminates the pattern <code>int [].
     */
    protected static final int MATCH_END = -3;

    /**
     * Determines if the pattern contains any * characters
     *
     * @param pattern The pattern
     * @return True if no wildcards are found
     */
    public boolean isLiteral(String pattern) {
        return (pattern == null || pattern.indexOf('*') == -1);
    }

    /**
     * <p> Translate the given String into a int []
     * representing the pattern matchable by this class. <br> This function
     * translates a <code>String into an int array converting the
     * special '*' and '\' characters. <br> Here is how the conversion
     * algorithm works:</p>
     *
     * <ul>
     *
     * <li>The '*' character is converted to MATCH_FILE, meaning that zero or
     * more characters (excluding the path separator '/') are to be
     * matched.</li>
     *
     * <li>The '**' sequence is converted to MATCH_PATH, meaning that zero or
     * more characters (including the path separator '/') are to be
     * matched.</li>
     *
     * <li>The '\' character is used as an escape sequence ('\*' is translated
     * in '*', not in MATCH_FILE). If an exact '\' character is to be matched
     * the source string must contain a '\\'. sequence.</li>
     *
     * </ul>
     *
     * <p>When more than two '*' characters, not separated by another
     * character, are found their value is considered as '**' (MATCH_PATH).
     * <br> The array is always terminated by a special value (MATCH_END).
     * <br> All MATCH* values are less than zero, while normal characters are
     * equal or greater.</p>
     *
     * @param data The string to translate.
     * @return The encoded string as an int array, terminated by the MATCH_END
     *         value (don't consider the array length).
     * @throws NullPointerException If data is null.
     */
    public int[] compilePattern(String data) {
        // Prepare the arrays
        int[] expr = new int[data.length() + 2];
        char[] buff = data.toCharArray();

        // Prepare variables for the translation loop
        int y = 0;
        boolean slash = false;

        // Must start from beginning
        expr[y++] = MATCH_BEGIN;

        if (buff.length > 0) {
            if (buff[0] == '\\') {
                slash = true;
            } else if (buff[0] == '*') {
                expr[y++] = MATCH_FILE;
            } else {
                expr[y++] = buff[0];
            }

            // Main translation loop
            for (int x = 1; x < buff.length; x++) {
                // If the previous char was '\' simply copy this char.
                if (slash) {
                    expr[y++] = buff[x];
                    slash = false;

                    // If the previous char was not '\' we have to do a bunch of
                    // checks
                } else {
                    // If this char is '\' declare that and continue
                    if (buff[x] == '\\') {
                        slash = true;

                        // If this char is '*' check the previous one
                    } else if (buff[x] == '*') {
                        // If the previous character als was '*' match a path
                        if (expr[y - 1] <= MATCH_FILE) {
                            expr[y - 1] = MATCH_PATH;
                        } else {
                            expr[y++] = MATCH_FILE;
                        }
                    } else {
                        expr[y++] = buff[x];
                    }
                }
            }
        }

        // Must match end at the end
        expr[y] = MATCH_THEEND;

        return expr;
    }

    /**
     * Match a pattern agains a string and isolates wildcard replacement into
     * a <code>Stack.
     *
     * @param map  The map to store matched values
     * @param data The string to match
     * @param expr The compiled wildcard expression
     * @return True if a match
     * @throws NullPointerException If any parameters are null
     */
    public boolean match(Map<String, String> map, String data, int[] expr) {
        if (map == null) {
            throw new NullPointerException("No map provided");
        }

        if (data == null) {
            throw new NullPointerException("No data provided");
        }

        if (expr == null) {
            throw new NullPointerException("No pattern expression provided");
        }

        char[] buff = data.toCharArray();

        // Allocate the result buffer
        char[] rslt = new char[expr.length + buff.length];

        // The previous and current position of the expression character
        // (MATCH_*)
        int charpos = 0;

        // The position in the expression, input, translation and result arrays
        int exprpos = 0;
        int buffpos = 0;
        int rsltpos = 0;
        int offset = -1;

        // The matching count
        int mcount = 0;

        // We want the complete data be in {0}
        map.put(Integer.toString(mcount), data);

        // First check for MATCH_BEGIN
        boolean matchBegin = false;

        if (expr[charpos] == MATCH_BEGIN) {
            matchBegin = true;
            exprpos = ++charpos;
        }

        // Search the fist expression character (except MATCH_BEGIN - already
        // skipped)
        while (expr[charpos] >= 0) {
            charpos++;
        }

        // The expression charater (MATCH_*)
        int exprchr = expr[charpos];

        while (true) {
            // Check if the data in the expression array before the current
            // expression character matches the data in the input buffer
            if (matchBegin) {
                if (!matchArray(expr, exprpos, charpos, buff, buffpos)) {
                    return (false);
                }

                matchBegin = false;
            } else {
                offset = indexOfArray(expr, exprpos, charpos, buff, buffpos);

                if (offset < 0) {
                    return (false);
                }
            }

            // Check for MATCH_BEGIN
            if (matchBegin) {
                if (offset != 0) {
                    return (false);
                }

                matchBegin = false;
            }

            // Advance buffpos
            buffpos += (charpos - exprpos);

            // Check for END's
            if (exprchr == MATCH_END) {
                if (rsltpos > 0) {
                    map.put(Integer.toString(++mcount),
                        new String(rslt, 0, rsltpos));
                }

                // Don't care about rest of input buffer
                return (true);
            } else if (exprchr == MATCH_THEEND) {
                if (rsltpos > 0) {
                    map.put(Integer.toString(++mcount),
                        new String(rslt, 0, rsltpos));
                }

                // Check that we reach buffer's end
                return (buffpos == buff.length);
            }

            // Search the next expression character
            exprpos = ++charpos;

            while (expr[charpos] >= 0) {
                charpos++;
            }

            int prevchr = exprchr;

            exprchr = expr[charpos];

            // We have here prevchr == * or **.
            offset =
                (prevchr == MATCH_FILE)
                ? indexOfArray(expr, exprpos, charpos, buff, buffpos)
                : lastIndexOfArray(expr, exprpos, charpos, buff, buffpos);

            if (offset < 0) {
                return (false);
            }

            // Copy the data from the source buffer into the result buffer
            // to substitute the expression character
            if (prevchr == MATCH_PATH) {
                while (buffpos < offset) {
                    rslt[rsltpos++] = buff[buffpos++];
                }
            } else {
                // Matching file, don't copy '/'
                while (buffpos < offset) {
                    if (buff[buffpos] == '/') {
                        return (false);
                    }

                    rslt[rsltpos++] = buff[buffpos++];
                }
            }

            map.put(Integer.toString(++mcount), new String(rslt, 0, rsltpos));
            rsltpos = 0;
        }
    }

    /**
     * Get the offset of a part of an int array within a char array. <br> This
     * method return the index in d of the first occurrence after dpos of that
     * part of array specified by r, starting at rpos and terminating at
     * rend.
     *
     * @param r    The array containing the data that need to be matched in
     *             d.
     * @param rpos The index of the first character in r to look for.
     * @param rend The index of the last character in r to look for plus 1.
     * @param d    The array of char that should contain a part of r.
     * @param dpos The starting offset in d for the matching.
     * @return The offset in d of the part of r matched in d or -1 if that was
     *         not found.
     */
    protected int indexOfArray(int[] r, int rpos, int rend, char[] d, int dpos) {
        // Check if pos and len are legal
        if (rend < rpos) {
            throw new IllegalArgumentException("rend < rpos");
        }

        // If we need to match a zero length string return current dpos
        if (rend == rpos) {
            return (d.length); //?? dpos?
        }

        // If we need to match a 1 char length string do it simply
        if ((rend - rpos) == 1) {
            // Search for the specified character
            for (int x = dpos; x < d.length; x++) {
                if (r[rpos] == d[x]) {
                    return (x);
                }
            }
        }

        // Main string matching loop. It gets executed if the characters to
        // match are less then the characters left in the d buffer
        while (((dpos + rend) - rpos) <= d.length) {
            // Set current startpoint in d
            int y = dpos;

            // Check every character in d for equity. If the string is matched
            // return dpos
            for (int x = rpos; x <= rend; x++) {
                if (x == rend) {
                    return (dpos);
                }

                if (r[x] != d[y++]) {
                    break;
                }
            }

            // Increase dpos to search for the same string at next offset
            dpos++;
        }

        // The remaining chars in d buffer were not enough or the string
        // wasn't matched
        return (-1);
    }

    /**
     * Get the offset of a last occurance of an int array within a char array.
     * <br> This method return the index in d of the last occurrence after
     * dpos of that part of array specified by r, starting at rpos and
     * terminating at rend.
     *
     * @param r    The array containing the data that need to be matched in
     *             d.
     * @param rpos The index of the first character in r to look for.
     * @param rend The index of the last character in r to look for plus 1.
     * @param d    The array of char that should contain a part of r.
     * @param dpos The starting offset in d for the matching.
     * @return The offset in d of the last part of r matched in d or -1 if
     *         that was not found.
     */
    protected int lastIndexOfArray(int[] r, int rpos, int rend, char[] d,
        int dpos) {
        // Check if pos and len are legal
        if (rend < rpos) {
            throw new IllegalArgumentException("rend < rpos");
        }

        // If we need to match a zero length string return current dpos
        if (rend == rpos) {
            return (d.length); //?? dpos?
        }

        // If we need to match a 1 char length string do it simply
        if ((rend - rpos) == 1) {
            // Search for the specified character
            for (int x = d.length - 1; x > dpos; x--) {
                if (r[rpos] == d[x]) {
                    return (x);
                }
            }
        }

        // Main string matching loop. It gets executed if the characters to
        // match are less then the characters left in the d buffer
        int l = d.length - (rend - rpos);

        while (l >= dpos) {
            // Set current startpoint in d
            int y = l;

            // Check every character in d for equity. If the string is matched
            // return dpos
            for (int x = rpos; x <= rend; x++) {
                if (x == rend) {
                    return (l);
                }

                if (r[x] != d[y++]) {
                    break;
                }
            }

            // Decrease l to search for the same string at next offset
            l--;
        }

        // The remaining chars in d buffer were not enough or the string
        // wasn't matched
        return (-1);
    }

    /**
     * Matches elements of array r from rpos to rend with array d, starting
     * from dpos. <br> This method return true if elements of array r from
     * rpos to rend equals elements of array d starting from dpos to
     * dpos+(rend-rpos).
     *
     * @param r    The array containing the data that need to be matched in
     *             d.
     * @param rpos The index of the first character in r to look for.
     * @param rend The index of the last character in r to look for.
     * @param d    The array of char that should start from a part of r.
     * @param dpos The starting offset in d for the matching.
     * @return true if array d starts from portion of array r.
     */
    protected boolean matchArray(int[] r, int rpos, int rend, char[] d, int dpos) {
        if ((d.length - dpos) < (rend - rpos)) {
            return (false);
        }

        for (int i = rpos; i < rend; i++) {
            if (r[i] != d[dpos++]) {
                return (false);
            }
        }

        return (true);
    }
}

Other Struts examples (source code examples)

Here is a short list of links related to this Struts WildcardHelper.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.