001package Torello.HTML;
002
003import java.util.regex.*;
004
005import Torello.HTML.parse.HTMLRegEx;
006
007/**
008 * This occurs whenever a parameter specifies an Inner-Tag
009 * <B STYLE="color: red;">"Key-Value Pair"</B> (which, in this package, are <I>also known
010 * as</I> Attribute-<B STYLE="color: red;">Value</B> Pairs) that contain inappropriate characters
011 * inside the {@code key-String}.
012 *
013 * <BR /><BR /><B>Rules State:</B> All matching HTML Element Attributes must have
014 * attribute-<B STYLE="color: red;">names</B> (inner-tags) whose nomenclature conforms to this
015 * regular-expression: {@code [A..Za..z][\w-]+}  All this says is that
016 * attribute-<B STYLE="color: red;">names</B> <I>must begin with an alphabetic character</I>, and 
017 * then the characters that follow must be "regular-expression" {@code word-characters '\w'}.  In a
018 * regular-expression, the characters that match a {@code \w} include the letters {@code A-Z}, the
019 * (lower-case) letters {@code a-z}, the digits {@code 0-9}, and the underscore {@code '_'}.  The
020 * minus-sign {@code '-'} may also be used in an attribute-<B STYLE="color: red;">name</B><I> (it 
021 * just may not be the first character used in an attribute-<B STYLE="color: red;">name</B>)</I>.
022 *
023 * <DIV CLASS="EXAMPLE">{@code 
024 *  <IMG SRC="http://example.com/pic.jpg">
025 *  <DIV data-id="this is example data">
026 * }</DIV>
027 * <BR />For the above two examples, both the {@code 'SRC'} attribute-name (key-name) and the
028 * {@code 'data-id'} key-<B STYLE="color: red;">name</B> are legitimately named.  No exceptions would
029 * be thrown if a programmer initiated a search using a string to look for an inner-tag that was named
030 * {@code 'src'} nor would there be problems using a string named {@code 'data-id'} to look for the
031 * <B STYLE="color: red;">value</B> of {@code data-id} above.
032 *
033 * <DIV CLASS="EXAMPLE">{@code 
034 * Properties p = new java.util.Properties();
035 * p.put("My Attribute Value", "data 1");
036 * p.put("123Attribute", "data 2");
037 * p.put("SpecialChars!@#$%", "data 3");
038 * TagNode tn = new TagNode("DIV", p, SD.DoubleQuotes, false);
039 * }</DIV>
040 * <BR />An {@code InnerTagKeyException} would be generated <I>for all three cases!</I>  Each of the
041 * above inner-tag <B STYLE="color: red;">key-value pairs</B> have key-<B STYLE="color: red;">names</B>
042 * with illegal characters.
043 * 
044 * <BR /><BR /><B>Specifically:</B>
045 * <BR /><BR /><UL CLASS="JDUL">
046 * <LI>Attribute-Value Pair 1: The key-<B STYLE="color: red;">name</B> contains a space.</LI>
047 * <LI>Attribute-Value Pair 2: The key-<B STYLE="color: red;">name</B> begins with a number.</LI>
048 * <LI>Attribute-Value Pair 3: The key-<B STYLE="color: red;">name</B> has invalid, non-alpha-numeric
049 *     characters!</LI>
050 * </UL>
051 * <BR />If a search were made using an inner-tag (attribute-<B STYLE="color: red;">name</B>) using
052 * a {@code String} that did not meet these criteria, an {@code InnerTagKeyException} would be thrown.
053 *
054 */
055public class InnerTagKeyException extends IllegalArgumentException
056{
057    /** <EMBED CLASS="external-html" DATA-FILE-ID="SVUIDEX"> */
058    public static final long serialVersionUID = 1;
059
060    /** Constructs an {@code InnerTagKeyException} with no detail message. */
061    public InnerTagKeyException()
062    { super(); }
063
064    /**
065     * Constructs an {@code InnerTagKeyException} with the specified detail message.
066     * @param message the detail message.
067     */
068    public InnerTagKeyException(String message)
069    { super(message); }
070
071    /**
072     * Constructs a new exception with the specified detail message and cause.
073     * <BR /><BR /><B>NOTE:</B> The detail message associated with cause is not automatically
074     * incorporated in this exception's detail message.
075     * @param message The detail message (which is saved for later retrieval by the
076     * {@code Throwable.getMessage()} method).
077     * @param cause the cause (which is saved for later retrieval by the {@code Throwable.getCause()}
078     * method).  (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
079     */
080    public InnerTagKeyException(String message, Throwable cause)
081    { super(message, cause); }
082
083    /**
084     * Constructs a new exception with the specified cause and a detail message of
085     * {@code (cause==null ? null : cause.toString())} (which typically contains the class and detail
086     * message of cause).
087     * This constructor is useful for exceptions that are little more than wrappers for other throwables.
088     * @param cause The cause (which is saved for later retrieval by the {@code Throwable.getCause()}
089     * method).  (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
090     */
091    public InnerTagKeyException(Throwable cause)
092    { super(cause); }
093
094    /**
095     * This verifies that any Java-{@code String} that is intended to be use as an inner-tag conforms
096     * to the right rules.  If a problem is found, then an {@code InnerTagKeyException} or
097     * {@code NullPointerException} is thrown.
098     * @param keys One or many HTML-Inner-Tag to be checked for use as an HTML-Attribute
099     * <B STYLE="color: red;">name</B>
100     * @throws InnerTagKeyException If any {@code String} does not match the {@code CHECK_KEY}
101     * Regular-Expression {@code Pattern}.
102     * @throws NullPointerException If any of the attributes / inner-tag <B STYLE="color: red;">keys</B>
103     * passed are null.
104     * @see TagNode.AttrRegEx#ATTRIBUTE_KEY_REGEX
105     */
106    public static void check(String... keys)
107    {
108        for (String key : keys)
109
110            if (key == null) throw new NullPointerException(
111                "You have passed a null as an Attribute-Name (also known as an " +
112                "'InnerTag-Key Name'), but this is not allowed."
113            );
114
115            else if (! TagNode.AttrRegEx.ATTRIBUTE_KEY_REGEX.matcher(key).find())
116                throw new InnerTagKeyException
117                    ("Inner-tag key has invalid characters: [" + key + ']');
118    }
119
120    /**
121     * This method is <B>identical</B> to the <B>{@code public static void check(key);}</B>, except
122     * it allows the programmer to add the <B STYLE="color: red;">key-value pair</B> to the 
123     * Exception's error message.  No change to the code is present, except the exception's error
124     * message.
125     * @param key Any HTML-Inner-Tag <B STYLE="color: red;">name</B>to be checked for use as an
126     * HTML-Attribute
127     * @param value This is the <B STYLE="color: red;">value</B> taken by this
128     * <B STYLE="color: red;">key</B>, it is included for error-logging only, but it is not checked.
129     * @throws InnerTagKeyException If this class does not match the {@code CHECK_KEY} 
130     * Regular-Expression {@code Pattern}, than it throws.
131     * @see TagNode.AttrRegEx#ATTRIBUTE_KEY_REGEX
132     */
133    public static void check(String key, String value)
134    {
135        if (key == null) throw new NullPointerException(
136            "You have passed a null as an Attribute-Name (also known as an 'InnerTag-Key Name'), " +
137            "but this is not allowed."
138        );
139
140        if (! TagNode.AttrRegEx.ATTRIBUTE_KEY_REGEX.matcher(key).find()) 
141            throw new InnerTagKeyException(
142                "The specified inner-tag key has invalid characters: [" + key + "]\n" +
143                "For Key-Value Pair: [" + key + ", " + value + "]"
144            );
145    }
146}