001package Torello.HTML.NodeSearch; 002 003import java.util.regex.*; 004import java.util.stream.Stream; 005 006import java.util.function.Predicate; 007 008import Torello.HTML.TagNode; 009 010/** 011 * An exception used for problems generated by either HTML-Tag <B>in-line</B> CSS 012 * <CODE>STYLE='...'</CODE> attributes, or by explicitly declared CSS 013 * <CODE><STYLE TYPE='text/css'></CODE> <B>style-blocks</B>. 014 * 015 * <BR /><BR /> 016 * This class does some passed-parameter checking for the HTML-Search routines. If one is 017 * using the {@code class TextComparitor}, it is important to remember that it usually works in 018 * coordination with Java's var-args syntax which allows anywhere from {@code '0'} to 019 * {@code 'n' String's}. This class of exception will be thrown if any one of the 020 * {@code String's} passed to the var-args parameter with the {@code TextComparitor} them has an 021 * invalid CSS Token according to the definition of valid CSS Naming-Convention Tokens. 022 * 023 * <BR /><BR /><B CLASS=JDDescLabel>NOTE:</B> 024 * 025 * <BR />This exception test is only performed when a {@link TextComparitor} is used with one of 026 * the {@link TagNode} CSS {@code 'class'} getter and setter methods, for example: 027 * {@link TagNode#setCSSClasses​(SD, boolean, String[])} 028 * 029 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=EXPM> 030 */ 031public class CSSStrException extends TCCompareStrException 032{ 033 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDEX> */ 034 public static final long serialVersionUID = 1; 035 036 /** 037 * This regular-expression can be used to identify valid versus invalid CSS Class-Names, and 038 * also CSS ID-Names. In English, this regular-expression says: A valid name should start with 039 * an underscore (_), a hyphen (-) or a letter (a-z) which is followed by any numbers, hyphens, 040 * underscores, letters. A name should be at least two characters long. Cannot start with a 041 * digit, two hyphens or a hyphen followed by a number. 042 */ 043 public static final Pattern VALID_CSS_CLASS_OR_NAME_TOKEN = 044 Pattern.compile("^[_\\-a-zA-Z]+[_\\-a-zA-Z0-9]*$"); 045 046 /** 047 * Regular-Expression as {@code Predicate<String>} 048 * @see #VALID_CSS_CLASS_OR_NAME_TOKEN 049 */ 050 public static final Predicate<String> VALID_CSS_CLASS_OR_NAME_TOKEN_PRED = 051 VALID_CSS_CLASS_OR_NAME_TOKEN.asPredicate(); 052 053 /** 054 * This constructor just calls the line: {@code super(message, compareStr, i);} 055 * 056 * @param message the detail message. 057 * 058 * @param compareStr This <I>SHOULD BE</I> the list of compare-strings that were passed to a 059 * TextComparitor that may have contained a null value, or was empty. It is important not to 060 * pass null for this parameter, because checking the input to an exception's constructor is 061 * not very wise... "Exceptions about Exceptions" is usually unintelligible to a programmer. 062 * 063 * @param i This is the index into the compareStr var-args parameter list that cause the 064 * exception to throw. 065 */ 066 public CSSStrException(String message, String[] compareStr, int i) 067 { super(message, compareStr, i); } 068 069 /** 070 * This constructor just calls the line: {@code super(message, cause, compareStr, i);} 071 * 072 * <BR /><BR /><DIV CLASS=JDHint> 073 * <B STYLE='color:red;'>Note:</B> The detail message associated with cause is not 074 * automatically incorporated into this exception's detail message. 075 * </DIV> 076 * 077 * @param message The detail message (which is saved for later retrieval by the 078 * {@code Throwable.getMessage()} method). 079 * 080 * @param cause This is sometimes used to "chain" exceptions in multi-threaded or heavily I/O 081 * related code. 082 * 083 * @param compareStr This <I>SHOULD BE</I> the list of compare-strings that were passed to a 084 * TextComparitor that may have contained a null value, or was empty. It is important not to 085 * pass null for this parameter, because checking the input to an exception's constructor is 086 * not very wise... "Exceptions about Exceptions" is usually unintelligible to a programmer. 087 * 088 * @param i This is the index into the compareStr var-args parameter list that cause the 089 * exception to throw. 090 */ 091 public CSSStrException(String message, Throwable cause, String[] compareStr, int i) 092 { super(message, cause, compareStr, i); } 093 094 /** 095 * This will do a simple test of the compare-{@code String's} to make sure none of them are 096 * null, and that there are at least one {@code String} in the array. 097 * 098 * <!-- This Explanation has been Copied from Torello.Java.StrCmprException --> 099 * <BR /><BR /><B CLASS=JDDescLabel>Explanation:</B> 100 * 101 * <BR />It is a subtle issue, but likely better to throw exceptions when one of the Varargs to 102 * a {@code String} comparison is {@code 'null'}. Since there is likely no general-convention 103 * or agreement on what {@code null} in the presence of {@code logical AND, OR, NOT, XOR, NAND} 104 * really means, throwing a {@code StrCmprException} <I>when even one var-args string-parameter 105 * is {@code 'null'}</I> actually makes the most sense. 106 * 107 * @param compareStr This should be the var-args parameter that was passed to a search method 108 * 109 * @throws CSSStrException If any of the elements of Var-Args parameter {@code 'compareStr'} 110 * is null, or if the array is zero-length. 111 * 112 * @see #VALID_CSS_CLASS_OR_NAME_TOKEN 113 * @see TCCompareStrException#check(String[]) 114 */ 115 public static void check(String... compareStr) 116 { 117 // Repackages the Exception into one with the name CSSStrException 118 try 119 { TCCompareStrException.check(compareStr); } 120 catch (TCCompareStrException e) 121 { 122 String[] tempV = new String[compareStr.length]; 123 throw new CSSStrException( 124 e.getMessage() + "\nSee getCause() for details.", 125 e, e.compareStrVec.toArray(tempV), e.i 126 ); 127 } 128 129 for (int i=0; i < compareStr.length; i++) 130 131 if (! VALID_CSS_CLASS_OR_NAME_TOKEN.matcher(compareStr[i]).find()) 132 133 throw new CSSStrException( 134 "One of the compare-strings passed to a search-method's var-args String " + 135 "parameter 'compareStr': [" + compareStr[i] + "]\n" + 136 "Did not pass the CSS Token-Naming Testing Regular-Expression: " + 137 "[" + VALID_CSS_CLASS_OR_NAME_TOKEN.pattern() + "]\n" + 138 "And this means it has been identified as an invalid CSS Token. " + 139 "This is not allowed here.\n" + 140 "If you are using TagNode.cssClasses(), switch to TagNode.AV('class').\n" + 141 "If you are using TextComparitor.CONTAINS_CSS_CLASS*, switch to " + 142 "TextComparitor.EQ_CI_TRM", 143 compareStr, i 144 ); 145 } 146 147 /** 148 * This will do a simple test of the compare-{@code String's} to make sure none of them are 149 * null, and that there are at least one {@code String} in the array. 150 * 151 * <!-- This Explanation has been Copied from Torello.Java.StrCmprException --> 152 * <BR /><BR /><B CLASS=JDDescLabel>Explanation:</B> 153 * 154 * <BR />It is a subtle issue, but likely better to throw exceptions when one of the Varargs to 155 * a {@code String} comparison is {@code 'null'}. Since there is likely no general-convention 156 * or agreement on what {@code null} in the presence of {@code logical AND, OR, NOT, XOR, NAND} 157 * really means, throwing a {@code StrCmprException} <I>when even one var-args string-parameter 158 * is {@code 'null'}</I> actually makes the most sense. 159 * 160 * @param compareStrs This should be the any instance of {@code Stream<String>} 161 * 162 * @throws CSSStrException If any of the elements of the {@code compareStrs} stream are null, 163 * or if the stream is empty. 164 * 165 * @see #VALID_CSS_CLASS_OR_NAME_TOKEN 166 * @see TCCompareStrException#check(String[]) 167 */ 168 public static Stream<String> check(Stream<String> compareStrs) 169 { 170 // Repackages the Exception into one with the name CSSStrException 171 String[] compareStr = compareStrs.toArray(String[]::new); 172 173 try 174 { TCCompareStrException.check(compareStr); } 175 catch (TCCompareStrException e) 176 { 177 String[] tempV = new String[compareStr.length]; 178 179 throw new CSSStrException( 180 e.getMessage() + "\nSee getCause() for details.", 181 e, e.compareStrVec.toArray(tempV), e.i 182 ); 183 } 184 185 for (int i=0; i < compareStr.length; i++) 186 187 if (! VALID_CSS_CLASS_OR_NAME_TOKEN.matcher(compareStr[i]).find()) 188 189 throw new CSSStrException( 190 "One of the compare-strings passed to a search-method's var-args String " + 191 "parameter 'compareStr': [" + compareStr[i] + "]\n" + 192 "Did not pass the CSS Token-Naming Testing Regular-Expression: " + 193 "[" + VALID_CSS_CLASS_OR_NAME_TOKEN.pattern() + "]\n" + 194 "And this means it has been identified as an invalid CSS Token. " + 195 "This is not allowed here.\n" + 196 "If you are using TagNode.cssClasses(), switch to TagNode.AV('class').\n" + 197 "If you are using TextComparitor.CONTAINS_CSS_CLASS*, switch to " + 198 "TextComparitor.EQ_CI_TRM", 199 compareStr, i 200 ); 201 202 return Stream.of(compareStr); 203 // The original stream is now empty! We must re-build it! 204 } 205}