litesoft
@ 965
litesoft / trunk / GWT_Sandbox / FormEngine / src / com / temp / foundation / client / support / ExceptionDisplayHelper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
package com.temp.foundation.client.support; import org.litesoft.externalization.shared.*; import com.temp.common.shared.utils.*; import com.temp.foundation.client.widget.dialog.*; import java.util.*; /** * Helper to create the: Title, Body text blocks, & an indicator regarding * displaying the Details button for the ExceptionDialog. * <p/> * The key to its flexibility and effectiveness is the application of the * "source", "context", and type of the "throwable" to a template source (in * this case the ExternalizedText object). By selecting different template * strings and then selectively either disabling different results or injecting * values, quite a variety of different looks can be achieved. * <p/> * The "source" is either from the RPCall's "callerSourceObject" and is the * Simple Class Name of this object (e.g. DashboardActivity), or "Uncaught". * <p/> * The "context" is null if the "source" is "Uncaught", otherwise it is the * Method Name from the "MethodWithExpectedExceptions" passed to the RPCall. * <p/> * The "throwable" is the problem either caught by the * "UncaughtExceptionHandler" or the un-handled problem fro mthe RPCall. * * @author georgs * @see E13nSubstitutionData */ public class ExceptionDisplayHelper { private static final String SUBSTITUTION_ID_NO_PREFIX = E13nResolver.INIT + "No"; // There are three Detail Button States: // // 1) {NoDetails} -> No Button // 2) {Details} -> I want the Details Button HERE // 3) Unspecified -> ExceptionDialog will add it where ever it wants... private static final String DEFAULT_SOURCE = E13nResolver.SPACE_SUBSTITUTION_ID + " " + ExceptionDialog.DETAILS_BUTTON_SUBSTITUTION_ID; // all the template keys for this class start with: private static final String KEY_NAME_PREFIX = "exception"; // Don't add the Details Button Indicator private static final String NO_DETAILS_BUTTON_SUBSTITUTION_ID = SUBSTITUTION_ID_NO_PREFIX + ExceptionDialog.DETAILS + E13nResolver.FINI; // Don't add the Additional Text blocks Indicator private static final String NO_ADDITIONAL_TEXT_SUBSTITUTION_ID = SUBSTITUTION_ID_NO_PREFIX + "AdditionalText" + E13nResolver.FINI; // Don't add the block named Indicator private static String noNamed( String name ) { return SUBSTITUTION_ID_NO_PREFIX + name + E13nResolver.FINI; } // Add the text associated with the name Indicator private static String named( String name ) { return E13nResolver.INIT + name + E13nResolver.FINI; } private final StringProxy titleText; private final StringProxy sourceText; private final StringProxy contextText; private final StringProxy typeText; private final StringProxy messageText; private final String[] additionalTextBlocks; private boolean noDetails, noAdditionalTextBlocks; public ExceptionDisplayHelper( E13nSubstitutionData sd, String source, String context, Throwable throwable, String... additionalTextBlocks ) { titleText = new StringProxy( sd, "Title" ); sourceText = new StringProxy( sd, "Source" ); contextText = new StringProxy( sd, "Context" ); typeText = new StringProxy( sd, "Type" ); messageText = new StringProxy( sd, "Message" ); this.additionalTextBlocks = additionalTextBlocks; source = Assert.noEmpty( "source", source ); context = StringUtils.noEmpty( context ); // Build Options such that there is always an empty string on the end: String[] sourceOptions = getSourceOptions( source ); String[] contextOptions = getContextOptions( context ); String[] typeOptions = getTypeOptions( throwable ); String type = typeOptions[0]; String message = throwable.getMessage(); // 1st set the base line texts from the template source appropriately titleText.setTextCombinatorically( sourceOptions, contextOptions, typeOptions, null ); sourceText.setTextCombinatorically( sourceOptions, contextOptions, typeOptions, DEFAULT_SOURCE ); contextText.setTextCombinatorically( sourceOptions, contextOptions, typeOptions, null ); typeText.setTextCombinatorically( sourceOptions, contextOptions, typeOptions, null ); messageText.setTextCombinatorically( sourceOptions, contextOptions, typeOptions, null ); // Disable each of the following if the others listed indicate. // This facilitates having to put fewer entries in the Template Source by // disabling "downstream" fields, e.g.: // exceptionTypeInvalidFilterNameException : "{NoMessage}{DontShow}" // would disable both the Type and Message display // exceptionSourceDashboardActivity : "{NoContext}{NoType}{NoMessage}...", // would disable Context, Type, & Message contextText.disableIfNoRequestedIn( sourceText, typeText, messageText ); typeText.disableIfNoRequestedIn( sourceText, contextText, messageText ); messageText.disableIfNoRequestedIn( sourceText, contextText, typeText ); // If source indicates, disable the Details button. noDetails = sourceText.noDetails(); // If any indicate, disable the Additional Text Blocks. noAdditionalTextBlocks = sourceText.noAdditionalText() | // Note the SINGLE '|' contextText.noAdditionalText() | // typeText.noAdditionalText() | // messageText.noAdditionalText(); // Now that all the "no" "flags" have been checked and removed, check if all that is left is the No Show request contextText.checkNoShow(); typeText.checkNoShow(); messageText.checkNoShow(); // Inject the actual text into self and others listed as desired/requested. // This facility has two purposes: // 1) Since each section is treated as a "paragraph" only eliminating & injecting can the "paragraphness" be eliminated. // 2) If you wanted to include some text, like the Exception Type in-line with some other text, it needs to be injected. contextText.injectActualTextInto( context, sourceText, typeText, messageText ); typeText.injectActualTextInto( type, sourceText, contextText, messageText ); messageText.injectActualTextInto( message, sourceText, contextText, typeText ); // Finish each - if No Add indicated anywhere above, then clear the text! sourceText.fini(); contextText.fini(); typeText.fini(); messageText.fini(); } public boolean noDetails() { return noDetails; } public String getTitle() { return titleText.text; } public String[] getTextBlocks() { List<String> blocks = new ArrayList<String>(); sourceText.addTo( blocks ); contextText.addTo( blocks ); typeText.addTo( blocks ); messageText.addTo( blocks ); if ( additionalTextBlocks != null && !noAdditionalTextBlocks ) { for ( String block : additionalTextBlocks ) { blocks.add( block ); } } return blocks.toArray( new String[blocks.size()] ); } private String[] getSourceOptions( String source ) { return new String[]{source, ""}; } private String[] getContextOptions( String context ) { return (context == null) ? new String[]{""} : new String[]{context, ""}; } private String[] getTypeOptions( Throwable throwable ) { Class<?> klass = throwable.getClass(); List<String> types = new ArrayList<String>(); do { types.add( ObjectUtils.getSimpleName( klass ) ); klass = klass.getSuperclass(); } while ( klass != null && klass != Object.class ); types.add( "" ); return types.toArray( new String[types.size()] ); } private static class StringProxy { private final E13nSubstitutionData sd; private final String prefix, namedSubId, noNamedSubId; private boolean noAdd = false; private String text = null; StringProxy( E13nSubstitutionData sd, String name ) { this.sd = sd; prefix = KEY_NAME_PREFIX + name; namedSubId = named( name ); noNamedSubId = noNamed( name ); } public boolean noDetails() { return (-1 != remove( NO_DETAILS_BUTTON_SUBSTITUTION_ID )); } public boolean noAdditionalText() { return (-1 != remove( NO_ADDITIONAL_TEXT_SUBSTITUTION_ID )); } public void disableIfNoRequestedIn( StringProxy... disablers ) { for ( StringProxy them : disablers ) { if ( -1 != them.remove( noNamedSubId ) ) { noAdd = true; } } } public void checkNoShow() { if ( -1 != remove( E13nResolver.DONT_SHOW_SUBSTITUTION_ID ) ) { noAdd = true; text = null; } } public void injectActualTextInto( String actualText, StringProxy... possibleRequestors ) { inject( namedSubId, actualText ); // self for ( StringProxy them : possibleRequestors ) { them.inject( namedSubId, actualText ); } } public void fini() { if ( noAdd ) { text = null; } } public void addTo( List<String> blocks ) { if ( text != null ) { blocks.add( text ); } } /** * Set the 'text' by trying all the Combinations in priority order: * <nl> * <li>SourceOptions</li> * <li>ContextOptions</li> * <li>TypeOptions</li> * </nl> * This results in: * <nl> * <li>SCTs</li> * <li>SC_</li> * <li>S_Ts</li> * <li>S__</li> * <li>_CTs</li> * <li>_C_</li> * <li>__Ts</li> * <li>___</li> * </nl> * * @param sourceOptions a two element array w/ the source and an empty string. * @param contextOptions a one or two element array based on if the context was not * null, with the last element being an empty String. * @param typeOptions the Throwable Type Hierarchy of Simple Class Names with a * trailing empty String */ public void setTextCombinatorically( String[] sourceOptions, String[] contextOptions, String[] typeOptions, String defaultValue ) { for ( int sourceIndex = 0; (text == null) && (sourceIndex < sourceOptions.length); sourceIndex++ ) { String sourcePrefix = prefix + sourceOptions[sourceIndex]; for ( int contextIndex = 0; (text == null) && (contextIndex < contextOptions.length); contextIndex++ ) { String contextPrefix = sourcePrefix + contextOptions[contextIndex]; for ( int typeIndex = 0; (text == null) && (typeIndex < typeOptions.length); typeIndex++ ) { text = sd.get( contextPrefix + typeOptions[typeIndex] ); } } } if ( text == null ) { text = defaultValue; } } private int remove( String textToFind ) { if ( text != null ) { int posAt = text.indexOf( textToFind ); if ( posAt != -1 ) { text = text.substring( 0, posAt ) + text.substring( posAt + textToFind.length() ); return posAt; } } return -1; } private void inject( String namedSubIdToRemove, String actualText ) { int posAt = remove( namedSubIdToRemove ); if ( (-1 != posAt) && (actualText != null) ) { text = text.substring( 0, posAt ) + actualText + text.substring( posAt ); } } } } |
Commits for litesoft/trunk/GWT_Sandbox/FormEngine/src/com/temp/foundation/client/support/ExceptionDisplayHelper.java
Revision | Author | Commited | Message |
---|---|---|---|
965 | GeorgeS | Fri 01 Aug, 2014 03:20:35 +0000 | ! |