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