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 * @param message The detail message (which is saved for later retrieval by the 073 * {@code Throwable.getMessage()} method). 074 * 075 * @param cause This is sometimes used to "chain" exceptions in multi-threaded or heavily I/O 076 * related code. 077 * 078 * @param compareStr This <I>SHOULD BE</I> the list of compare-strings that were passed to a 079 * TextComparitor that may have contained a null value, or was empty. It is important not to 080 * pass null for this parameter, because checking the input to an exception's constructor is 081 * not very wise... "Exceptions about Exceptions" is usually unintelligible to a programmer. 082 * 083 * @param i This is the index into the compareStr var-args parameter list that cause the 084 * exception to throw. 085 */ 086 public CSSStrException(String message, Throwable cause, String[] compareStr, int i) 087 { super(message, cause, compareStr, i); } 088 089 /** 090 * This will do a simple test of the compare-{@code String's} to make sure none of them are 091 * null, and that there are at least one {@code String} in the array. 092 * 093 * <!-- This Explanation has been Copied from Torello.Java.StrCmprException --> 094 * <BR /><BR /><B CLASS=JDDescLabel>Explanation:</B> 095 * 096 * <BR />It is a subtle issue, but likely better to throw exceptions when one of the Varargs to 097 * a {@code String} comparison is {@code 'null'}. Since there is likely no general-convention 098 * or agreement on what {@code null} in the presence of {@code logical AND, OR, NOT, XOR, NAND} 099 * really means, throwing a {@code StrCmprException} <I>when even one var-args string-parameter 100 * is {@code 'null'}</I> actually makes the most sense. 101 * 102 * @param compareStr This should be the var-args parameter that was passed to a search method 103 * 104 * @throws CSSStrException If any of the elements of Var-Args parameter {@code 'compareStr'} 105 * is null, or if the array is zero-length. 106 * 107 * @see #VALID_CSS_CLASS_OR_NAME_TOKEN 108 * @see TCCompareStrException#check(String[]) 109 */ 110 public static void check(String... compareStr) 111 { 112 // Repackages the Exception into one with the name CSSStrException 113 try 114 { TCCompareStrException.check(compareStr); } 115 catch (TCCompareStrException e) 116 { 117 String[] tempV = new String[compareStr.length]; 118 throw new CSSStrException( 119 e.getMessage() + "\nSee getCause() for details.", 120 e, e.compareStrVec.toArray(tempV), e.i 121 ); 122 } 123 124 for (int i=0; i < compareStr.length; i++) 125 126 if (! VALID_CSS_CLASS_OR_NAME_TOKEN.matcher(compareStr[i]).find()) 127 128 throw new CSSStrException( 129 "One of the compare-strings passed to a search-method's var-args String " + 130 "parameter 'compareStr': [" + compareStr[i] + "]\n" + 131 "Did not pass the CSS Token-Naming Testing Regular-Expression: " + 132 "[" + VALID_CSS_CLASS_OR_NAME_TOKEN.pattern() + "]\n" + 133 "And this means it has been identified as an invalid CSS Token. " + 134 "This is not allowed here.\n" + 135 "If you are using TagNode.cssClasses(), switch to TagNode.AV('class').\n" + 136 "If you are using TextComparitor.CONTAINS_CSS_CLASS*, switch to " + 137 "TextComparitor.EQ_CI_TRM", 138 compareStr, i 139 ); 140 } 141 142 /** 143 * This will do a simple test of the compare-{@code String's} to make sure none of them are 144 * null, and that there are at least one {@code String} in the array. 145 * 146 * <!-- This Explanation has been Copied from Torello.Java.StrCmprException --> 147 * <BR /><BR /><B CLASS=JDDescLabel>Explanation:</B> 148 * 149 * <BR />It is a subtle issue, but likely better to throw exceptions when one of the Varargs to 150 * a {@code String} comparison is {@code 'null'}. Since there is likely no general-convention 151 * or agreement on what {@code null} in the presence of {@code logical AND, OR, NOT, XOR, NAND} 152 * really means, throwing a {@code StrCmprException} <I>when even one var-args string-parameter 153 * is {@code 'null'}</I> actually makes the most sense. 154 * 155 * @param compareStrs This should be the any instance of {@code Stream<String>} 156 * 157 * @throws CSSStrException If any of the elements of the {@code compareStrs} stream are null, 158 * or if the stream is empty. 159 * 160 * @see #VALID_CSS_CLASS_OR_NAME_TOKEN 161 * @see TCCompareStrException#check(String[]) 162 */ 163 public static Stream<String> check(Stream<String> compareStrs) 164 { 165 // Repackages the Exception into one with the name CSSStrException 166 String[] compareStr = compareStrs.toArray(String[]::new); 167 168 try 169 { TCCompareStrException.check(compareStr); } 170 catch (TCCompareStrException e) 171 { 172 String[] tempV = new String[compareStr.length]; 173 174 throw new CSSStrException( 175 e.getMessage() + "\nSee getCause() for details.", 176 e, e.compareStrVec.toArray(tempV), e.i 177 ); 178 } 179 180 for (int i=0; i < compareStr.length; i++) 181 182 if (! VALID_CSS_CLASS_OR_NAME_TOKEN.matcher(compareStr[i]).find()) 183 184 throw new CSSStrException( 185 "One of the compare-strings passed to a search-method's var-args String " + 186 "parameter 'compareStr': [" + compareStr[i] + "]\n" + 187 "Did not pass the CSS Token-Naming Testing Regular-Expression: " + 188 "[" + VALID_CSS_CLASS_OR_NAME_TOKEN.pattern() + "]\n" + 189 "And this means it has been identified as an invalid CSS Token. " + 190 "This is not allowed here.\n" + 191 "If you are using TagNode.cssClasses(), switch to TagNode.AV('class').\n" + 192 "If you are using TextComparitor.CONTAINS_CSS_CLASS*, switch to " + 193 "TextComparitor.EQ_CI_TRM", 194 compareStr, i 195 ); 196 197 return Stream.of(compareStr); 198 // The original stream is now empty! We must re-build it! 199 } 200}