~ubuntu-branches/ubuntu/wily/aspectj/wily-proposed

« back to all changes in this revision

Viewing changes to org.aspectj/modules/bridge/src/org/aspectj/bridge/MessageUtil.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2011-03-15 23:54:31 UTC
  • mfrom: (1.2.5 upstream)
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20110315235431-iq2gxbsx08kpwuiw
* New upstream release.
* Updated Standards-Version to 3.9.1 (no changes needed).
* Fix local Javadoc links:
  - d/patches/07_javadoc_links.diff: Use locally installed
   javadoc packages and hyperlink with them.
  - d/control: Add B-D on default-java-doc and libasm3-java-doc.
* d/control: Drop B-D on itself (our new bootstrap infrastructure doesn't need
  that anymore).
* Split packages into :
  - aspectj: only contains CLI tools.
  - libaspectj-java: JAR librairies for /usr/share/java.
  - libaspectj-java-doc: 4 API's Javadoc.
  - aspectj-doc: Programming Guides and SDK Documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 
14
14
package org.aspectj.bridge;
15
15
 
16
 
import java.io.*;
17
 
import java.util.*;
 
16
import java.io.File;
 
17
import java.io.IOException;
 
18
import java.io.OutputStream;
 
19
import java.io.PrintStream;
 
20
import java.io.PrintWriter;
 
21
import java.io.StringWriter;
 
22
import java.util.ArrayList;
 
23
import java.util.Arrays;
 
24
import java.util.Collection;
 
25
import java.util.Collections;
 
26
import java.util.Iterator;
 
27
import java.util.List;
18
28
 
19
29
import org.aspectj.bridge.IMessage.Kind;
20
 
import org.aspectj.util.*;
 
30
import org.aspectj.util.LangUtil;
21
31
 
22
32
/**
23
33
 * Convenience API's for constructing, printing, and sending messages.
24
34
 */
25
35
public class MessageUtil {
26
 
    
27
 
    // ------ some constant, content-less messages
28
 
    // no variants for "info" or "debug", which should always have content
29
 
    public static final IMessage ABORT_NOTHING_TO_RUN 
30
 
        = new Message("aborting - nothing to run", IMessage.ABORT, null, null);
31
 
 
32
 
    public static final IMessage FAIL_INCOMPLETE 
33
 
        = new Message("run not completed", IMessage.FAIL, null, null);
34
 
 
35
 
    public static final IMessage ABORT_NOMESSAGE 
36
 
        = new Message("", IMessage.ABORT, null, null);
37
 
 
38
 
    public static final IMessage FAIL_NOMESSAGE 
39
 
        = new Message("", IMessage.FAIL, null, null);
40
 
 
41
 
    public static final IMessage ERROR_NOMESSAGE 
42
 
        = new Message("", IMessage.ERROR, null, null);
43
 
 
44
 
    public static final IMessage WARNING_NOMESSAGE 
45
 
        = new Message("", IMessage.WARNING, null, null);
46
 
        
47
 
    
48
 
    /** handle abort message (ignored if handler is null) */
49
 
    public static boolean abort(IMessageHandler handler, String message) {
50
 
        return ((null != handler)
51
 
            && handler.handleMessage(abort(message)));
52
 
    }
53
 
 
54
 
    /** create and handle exception message (ignored if handler is null) */
55
 
    public static boolean abort(IMessageHandler handler, String message, Throwable t) {
56
 
        if (handler != null) return handler.handleMessage(abort(message, t));
57
 
        return false;
58
 
    }
59
 
 
60
 
    /** create and handle fail message (ignored if handler is null) */
61
 
    public static boolean fail(IMessageHandler handler, String message) {
62
 
        return ((null != handler)
63
 
            && handler.handleMessage(fail(message)));
64
 
    }
65
 
 
66
 
//    /** create and handle fail message from reader (ignored if handler is null) */
67
 
//    public static boolean fail(IMessageHandler handler, String message, LineReader reader) {
68
 
//        return ((null != handler)
69
 
//            && handler.handleMessage(fail(message, reader)));
70
 
//    }
71
 
    
72
 
    /** create and handle fail message (ignored if handler is null) */
73
 
    public static boolean fail(IMessageHandler handler, String message, Throwable thrown) {
74
 
        return ((null != handler)
75
 
            && handler.handleMessage(fail(message, thrown)));
76
 
    }
77
 
 
78
 
    /** create and handle error message (ignored if handler is null) */
79
 
    public static boolean error(IMessageHandler handler, String message) {
80
 
        return ((null != handler)
81
 
            && handler.handleMessage(error(message)));
82
 
    }
83
 
 
84
 
    /** create and handle warn message (ignored if handler is null) */
85
 
    public static boolean warn(IMessageHandler handler, String message) {
86
 
        return ((null != handler)
87
 
            && handler.handleMessage(warn(message)));
88
 
    }
89
 
 
90
 
    /** create and handle debug message (ignored if handler is null) */
91
 
    public static boolean debug(IMessageHandler handler, String message) {
92
 
        return ((null != handler)
93
 
            && handler.handleMessage(debug(message)));
94
 
    }
95
 
 
96
 
    /** create and handle info message (ignored if handler is null) */
97
 
    public static boolean info(IMessageHandler handler, String message) {
98
 
        return ((null != handler)
99
 
            && handler.handleMessage(info(message)));
100
 
    }
101
 
 
102
 
    /** @return ABORT_NOMESSAGE if message is empty or IMessage otherwise */ // 
103
 
    public static IMessage abort(String message) {
104
 
        if (LangUtil.isEmpty(message)) {
105
 
            return ABORT_NOMESSAGE;
106
 
        } else {
107
 
            return new Message(message, IMessage.ABORT, null, null);
108
 
        }
109
 
    }
110
 
 
111
 
    /** @return abort IMessage with thrown and message o
112
 
     * ABORT_NOMESSAGE if both are empty/null */ // 
113
 
    public static IMessage abort(String message, Throwable thrown) {
114
 
        if (!LangUtil.isEmpty(message)) {
115
 
            return new Message(message, IMessage.ABORT, thrown, null);
116
 
        } else if (null == thrown) {
117
 
            return ABORT_NOMESSAGE;
118
 
        } else {
119
 
            return new Message(thrown.getMessage(), IMessage.ABORT, thrown, null);
120
 
        }
121
 
    }
122
 
 
123
 
    /** @return FAIL_NOMESSAGE if message is empty or IMessage otherwise */
124
 
    public static IMessage fail(String message) {
125
 
        if (LangUtil.isEmpty(message)) {
126
 
            return FAIL_NOMESSAGE;
127
 
        } else {
128
 
          return new Message(message, IMessage.FAIL, null, ISourceLocation.EMPTY);
129
 
 
130
 
//            return fail(message, (LineReader) null);
131
 
        }
132
 
    }
133
 
    
134
 
    /** 
135
 
     * Create fail message.
136
 
     * If message is empty but thrown is not, use thrown.getMessage() as the message.
137
 
     * If message is empty and thrown is null, return FAIL_NOMESSAGE.
138
 
     * @return FAIL_NOMESSAGE if thrown is null and message is empty 
139
 
     * or IMessage FAIL with message and thrown otherwise 
140
 
     */
141
 
    public static IMessage fail(String message, Throwable thrown) {
142
 
        if (LangUtil.isEmpty(message)) {
143
 
            if (null == thrown) {
144
 
                return FAIL_NOMESSAGE;
145
 
            } else {
146
 
                return new Message(thrown.getMessage(), IMessage.FAIL, thrown, null);
147
 
            }
148
 
        } else {
149
 
            return new Message(message, IMessage.FAIL, thrown, null);
150
 
        }
151
 
    }
152
 
    
153
 
    /** 
154
 
     * @return IMessage with IMessage.Kind FAIL and message as text 
155
 
     * and soure location from reader 
156
 
     */
157
 
//    public static IMessage fail(String message) {//, LineReader reader) {
158
 
//        ISourceLocation loc = null;
159
 
//        if (null == reader) {
160
 
//            loc = ISourceLocation.EMPTY;
161
 
//        } else {
162
 
//            int line = reader.getLineNumber();
163
 
//            if (0 < line) {
164
 
//                line = 0;
165
 
//            }        
166
 
//            loc = new SourceLocation(reader.getFile(), line, line, 0);
167
 
//        }
168
 
//        return new Message(message, IMessage.FAIL, null, ISourceLocation.EMPTY);
169
 
//    }
170
 
 
171
 
    /** @return ERROR_NOMESSAGE if message is empty or IMessage otherwise */ // 
172
 
    public static IMessage error(String message, ISourceLocation location) {
173
 
        if (LangUtil.isEmpty(message)) {
174
 
            return ERROR_NOMESSAGE;
175
 
        } else {
176
 
            return new Message(message, IMessage.ERROR, null, location);
177
 
        }
178
 
    }
179
 
 
180
 
    /** @return WARNING_NOMESSAGE if message is empty or IMessage otherwise */ // 
181
 
    public static IMessage warn(String message, ISourceLocation location) {
182
 
        if (LangUtil.isEmpty(message)) {
183
 
            return WARNING_NOMESSAGE;
184
 
        } else {
185
 
            return new Message(message, IMessage.WARNING, null, location);
186
 
        }
187
 
    }
188
 
    /** @return ERROR_NOMESSAGE if message is empty or IMessage otherwise */ // 
189
 
    public static IMessage error(String message) {
190
 
        if (LangUtil.isEmpty(message)) {
191
 
            return ERROR_NOMESSAGE;
192
 
        } else {
193
 
            return new Message(message, IMessage.ERROR, null, null);
194
 
        }
195
 
    }
196
 
 
197
 
    /** @return WARNING_NOMESSAGE if message is empty or IMessage otherwise */ // 
198
 
    public static IMessage warn(String message) {
199
 
        if (LangUtil.isEmpty(message)) {
200
 
            return WARNING_NOMESSAGE;
201
 
        } else {
202
 
            return new Message(message, IMessage.WARNING, null, null);
203
 
        }
204
 
    }
205
 
 
206
 
    /** @return IMessage.DEBUG message with message content */
207
 
    public static IMessage debug(String message) {
208
 
        return new Message(message, IMessage.DEBUG, null, null);
209
 
    }
210
 
 
211
 
    /** @return IMessage.INFO message with message content */
212
 
    public static IMessage info(String message) {
213
 
        return new Message(message, IMessage.INFO, null, null);
214
 
    }
215
 
 
216
 
//    /** @return ISourceLocation with the current File/line of the reader */
217
 
//    public static ISourceLocation makeSourceLocation(LineReader reader) {
218
 
//        LangUtil.throwIaxIfNull(reader, "reader");
219
 
//        
220
 
//        int line = reader.getLineNumber();
221
 
//        if (0 < line) {
222
 
//            line = 0;
223
 
//        }        
224
 
//        return new SourceLocation(reader.getFile(), line, line, 0);
225
 
//    }
226
 
    
227
 
    // ------------------------ printing messages
228
 
    /**
229
 
     * Print total counts message to the print stream, starting each on a new line
230
 
     * @param messageHolder
231
 
     * @param out
232
 
     */
233
 
    public static void printMessageCounts(PrintStream out, IMessageHolder messageHolder) {
234
 
        if ((null == out) || (null == messageHolder)) {
235
 
            return;
236
 
        }
237
 
        printMessageCounts(out, messageHolder, "");
238
 
    }
239
 
    
240
 
    public static void printMessageCounts(PrintStream out, IMessageHolder holder, String prefix) {
241
 
        out.println(prefix + "MessageHolder: " + MessageUtil.renderCounts(holder));
242
 
    }
 
36
 
 
37
        // ------ some constant, content-less messages
 
38
        // no variants for "info" or "debug", which should always have content
 
39
        public static final IMessage ABORT_NOTHING_TO_RUN = new Message("aborting - nothing to run", IMessage.ABORT, null, null);
 
40
 
 
41
        public static final IMessage FAIL_INCOMPLETE = new Message("run not completed", IMessage.FAIL, null, null);
 
42
 
 
43
        public static final IMessage ABORT_NOMESSAGE = new Message("", IMessage.ABORT, null, null);
 
44
 
 
45
        public static final IMessage FAIL_NOMESSAGE = new Message("", IMessage.FAIL, null, null);
 
46
 
 
47
        public static final IMessage ERROR_NOMESSAGE = new Message("", IMessage.ERROR, null, null);
 
48
 
 
49
        public static final IMessage WARNING_NOMESSAGE = new Message("", IMessage.WARNING, null, null);
 
50
 
 
51
        /** handle abort message (ignored if handler is null) */
 
52
        public static boolean abort(IMessageHandler handler, String message) {
 
53
                return ((null != handler) && handler.handleMessage(abort(message)));
 
54
        }
 
55
 
 
56
        /** create and handle exception message (ignored if handler is null) */
 
57
        public static boolean abort(IMessageHandler handler, String message, Throwable t) {
 
58
                if (handler != null) {
 
59
                        return handler.handleMessage(abort(message, t));
 
60
                }
 
61
                return false;
 
62
        }
 
63
 
 
64
        /** create and handle fail message (ignored if handler is null) */
 
65
        public static boolean fail(IMessageHandler handler, String message) {
 
66
                return ((null != handler) && handler.handleMessage(fail(message)));
 
67
        }
 
68
 
 
69
        // /** create and handle fail message from reader (ignored if handler is null) */
 
70
        // public static boolean fail(IMessageHandler handler, String message, LineReader reader) {
 
71
        // return ((null != handler)
 
72
        // && handler.handleMessage(fail(message, reader)));
 
73
        // }
 
74
 
 
75
        /** create and handle fail message (ignored if handler is null) */
 
76
        public static boolean fail(IMessageHandler handler, String message, Throwable thrown) {
 
77
                return ((null != handler) && handler.handleMessage(fail(message, thrown)));
 
78
        }
 
79
 
 
80
        /** create and handle error message (ignored if handler is null) */
 
81
        public static boolean error(IMessageHandler handler, String message) {
 
82
                return ((null != handler) && handler.handleMessage(error(message)));
 
83
        }
 
84
 
 
85
        /** create and handle warn message (ignored if handler is null) */
 
86
        public static boolean warn(IMessageHandler handler, String message) {
 
87
                return ((null != handler) && handler.handleMessage(warn(message)));
 
88
        }
 
89
 
 
90
        /** create and handle debug message (ignored if handler is null) */
 
91
        public static boolean debug(IMessageHandler handler, String message) {
 
92
                return ((null != handler) && handler.handleMessage(debug(message)));
 
93
        }
 
94
 
 
95
        /** create and handle info message (ignored if handler is null) */
 
96
        public static boolean info(IMessageHandler handler, String message) {
 
97
                return ((null != handler) && handler.handleMessage(info(message)));
 
98
        }
 
99
 
 
100
        /** @return ABORT_NOMESSAGE if message is empty or IMessage otherwise */
 
101
        //
 
102
        public static IMessage abort(String message) {
 
103
                if (LangUtil.isEmpty(message)) {
 
104
                        return ABORT_NOMESSAGE;
 
105
                } else {
 
106
                        return new Message(message, IMessage.ABORT, null, null);
 
107
                }
 
108
        }
 
109
 
 
110
        /**
 
111
         * @return abort IMessage with thrown and message o ABORT_NOMESSAGE if both are empty/null
 
112
         */
 
113
        //
 
114
        public static IMessage abort(String message, Throwable thrown) {
 
115
                if (!LangUtil.isEmpty(message)) {
 
116
                        return new Message(message, IMessage.ABORT, thrown, null);
 
117
                } else if (null == thrown) {
 
118
                        return ABORT_NOMESSAGE;
 
119
                } else {
 
120
                        return new Message(thrown.getMessage(), IMessage.ABORT, thrown, null);
 
121
                }
 
122
        }
 
123
 
 
124
        /** @return FAIL_NOMESSAGE if message is empty or IMessage otherwise */
 
125
        public static IMessage fail(String message) {
 
126
                if (LangUtil.isEmpty(message)) {
 
127
                        return FAIL_NOMESSAGE;
 
128
                } else {
 
129
                        return new Message(message, IMessage.FAIL, null, ISourceLocation.EMPTY);
 
130
 
 
131
                        // return fail(message, (LineReader) null);
 
132
                }
 
133
        }
 
134
 
 
135
        /**
 
136
         * Create fail message. If message is empty but thrown is not, use thrown.getMessage() as the message. If message is empty and
 
137
         * thrown is null, return FAIL_NOMESSAGE.
 
138
         * 
 
139
         * @return FAIL_NOMESSAGE if thrown is null and message is empty or IMessage FAIL with message and thrown otherwise
 
140
         */
 
141
        public static IMessage fail(String message, Throwable thrown) {
 
142
                if (LangUtil.isEmpty(message)) {
 
143
                        if (null == thrown) {
 
144
                                return FAIL_NOMESSAGE;
 
145
                        } else {
 
146
                                return new Message(thrown.getMessage(), IMessage.FAIL, thrown, null);
 
147
                        }
 
148
                } else {
 
149
                        return new Message(message, IMessage.FAIL, thrown, null);
 
150
                }
 
151
        }
 
152
 
 
153
        /**
 
154
         * @return IMessage with IMessage.Kind FAIL and message as text and soure location from reader
 
155
         */
 
156
        // public static IMessage fail(String message) {//, LineReader reader) {
 
157
        // ISourceLocation loc = null;
 
158
        // if (null == reader) {
 
159
        // loc = ISourceLocation.EMPTY;
 
160
        // } else {
 
161
        // int line = reader.getLineNumber();
 
162
        // if (0 < line) {
 
163
        // line = 0;
 
164
        // }
 
165
        // loc = new SourceLocation(reader.getFile(), line, line, 0);
 
166
        // }
 
167
        // return new Message(message, IMessage.FAIL, null, ISourceLocation.EMPTY);
 
168
        // }
 
169
 
 
170
        /** @return ERROR_NOMESSAGE if message is empty or IMessage otherwise */
 
171
        //
 
172
        public static IMessage error(String message, ISourceLocation location) {
 
173
                if (LangUtil.isEmpty(message)) {
 
174
                        return ERROR_NOMESSAGE;
 
175
                } else {
 
176
                        return new Message(message, IMessage.ERROR, null, location);
 
177
                }
 
178
        }
 
179
 
 
180
        /** @return WARNING_NOMESSAGE if message is empty or IMessage otherwise */
 
181
        //
 
182
        public static IMessage warn(String message, ISourceLocation location) {
 
183
                if (LangUtil.isEmpty(message)) {
 
184
                        return WARNING_NOMESSAGE;
 
185
                } else {
 
186
                        return new Message(message, IMessage.WARNING, null, location);
 
187
                }
 
188
        }
 
189
 
 
190
        /** @return ERROR_NOMESSAGE if message is empty or IMessage otherwise */
 
191
        //
 
192
        public static IMessage error(String message) {
 
193
                if (LangUtil.isEmpty(message)) {
 
194
                        return ERROR_NOMESSAGE;
 
195
                } else {
 
196
                        return new Message(message, IMessage.ERROR, null, null);
 
197
                }
 
198
        }
 
199
 
 
200
        /** @return WARNING_NOMESSAGE if message is empty or IMessage otherwise */
 
201
        //
 
202
        public static IMessage warn(String message) {
 
203
                if (LangUtil.isEmpty(message)) {
 
204
                        return WARNING_NOMESSAGE;
 
205
                } else {
 
206
                        return new Message(message, IMessage.WARNING, null, null);
 
207
                }
 
208
        }
 
209
 
 
210
        /** @return IMessage.DEBUG message with message content */
 
211
        public static IMessage debug(String message) {
 
212
                return new Message(message, IMessage.DEBUG, null, null);
 
213
        }
 
214
 
 
215
        /** @return IMessage.INFO message with message content */
 
216
        public static IMessage info(String message) {
 
217
                return new Message(message, IMessage.INFO, null, null);
 
218
        }
 
219
 
 
220
        // /** @return ISourceLocation with the current File/line of the reader */
 
221
        // public static ISourceLocation makeSourceLocation(LineReader reader) {
 
222
        // LangUtil.throwIaxIfNull(reader, "reader");
 
223
        //
 
224
        // int line = reader.getLineNumber();
 
225
        // if (0 < line) {
 
226
        // line = 0;
 
227
        // }
 
228
        // return new SourceLocation(reader.getFile(), line, line, 0);
 
229
        // }
 
230
 
 
231
        // ------------------------ printing messages
 
232
        /**
 
233
         * Print total counts message to the print stream, starting each on a new line
 
234
         * 
 
235
         * @param messageHolder
 
236
         * @param out
 
237
         */
 
238
        public static void printMessageCounts(PrintStream out, IMessageHolder messageHolder) {
 
239
                if ((null == out) || (null == messageHolder)) {
 
240
                        return;
 
241
                }
 
242
                printMessageCounts(out, messageHolder, "");
 
243
        }
 
244
 
 
245
        public static void printMessageCounts(PrintStream out, IMessageHolder holder, String prefix) {
 
246
                out.println(prefix + "MessageHolder: " + MessageUtil.renderCounts(holder));
 
247
        }
 
248
 
243
249
        /**
244
250
         * Print all message to the print stream, starting each on a new line
 
251
         * 
245
252
         * @param messageHolder
246
253
         * @param out
247
 
     * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
 
254
         * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
248
255
         */
249
256
        public static void print(PrintStream out, IMessageHolder messageHolder) {
250
 
        print(out, messageHolder, (String) null, (IMessageRenderer) null, (IMessageHandler) null);
251
 
    }
252
 
            
253
 
    /**
254
 
     * Print all message to the print stream, starting each on a new line,
255
 
     * with a prefix.
256
 
     * @param messageHolder
257
 
     * @param out
258
 
     * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
259
 
     */
260
 
    public static void print(PrintStream out, IMessageHolder holder, String prefix) {
261
 
        print(out, holder, prefix, (IMessageRenderer) null, (IMessageHandler) null);
262
 
    }
263
 
    
264
 
    /**
265
 
     * Print all message to the print stream, starting each on a new line,
266
 
     * with a prefix and using a renderer.
267
 
     * @param messageHolder
268
 
     * @param out
269
 
     * @param renderer IMessageRender to render result - use MESSAGE_LINE if null
270
 
     * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
271
 
     */
272
 
    public static void print(PrintStream out, IMessageHolder holder, String prefix,
273
 
        IMessageRenderer renderer) {
274
 
        print(out, holder, prefix, renderer, (IMessageHandler) null);
275
 
    }
276
 
        
277
 
    /**
278
 
     * Print all message to the print stream, starting each on a new line,
279
 
     * with a prefix and using a renderer.
280
 
     * The first line renders a summary: {prefix}MessageHolder: {summary}
281
 
     * Each message line has the following form:
282
 
     *   <pre>{prefix}[{kind} {index}]: {rendering}</pre>
283
 
     * (where "{index}" (length 3) is the position within
284
 
     * the set of like-kinded messages, ignoring selector omissions.
285
 
     * Renderers are free to render multi-line output.
286
 
     * @param out the PrintStream sink - return silently if null
287
 
     * @param messageHolder the IMessageHolder with the messages to print
288
 
     * @param renderer IMessageRender to render result - use MESSAGE_ALL if null
289
 
     * @param selector IMessageHandler to select messages to render - if null, do all non-null
290
 
     */
291
 
    public static void print(PrintStream out, IMessageHolder holder, String prefix,
292
 
        IMessageRenderer renderer, IMessageHandler selector) {
293
 
        print(out, holder, prefix, renderer, selector, true);
294
 
    }
295
 
    
296
 
    public static void print(PrintStream out, IMessageHolder holder, String prefix,
297
 
        IMessageRenderer renderer, IMessageHandler selector, boolean printSummary) {
298
 
        if ((null == out) || (null == holder)) {
299
 
            return;
300
 
        }
301
 
        if (null == renderer) {
302
 
            renderer = MESSAGE_ALL;
303
 
        }
304
 
        if (null == selector) {
305
 
            selector = PICK_ALL;
306
 
        }
307
 
        if (printSummary) {
308
 
            out.println(prefix + "MessageHolder: " + MessageUtil.renderCounts(holder));
309
 
        }
310
 
        for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
311
 
            IMessage.Kind kind = (IMessage.Kind) iter.next();
312
 
            if (!selector.isIgnoring(kind)) {
313
 
                IMessage[] messages = holder.getMessages(kind, IMessageHolder.EQUAL);
314
 
                for (int i = 0; i < messages.length; i++) {
315
 
                    if (selector.handleMessage(messages[i])) {
316
 
                        String label = (null == prefix
317
 
                            ? ""
318
 
                            : prefix + "[" + kind + " " + LangUtil.toSizedString(i, 3) + "]: ");
319
 
                        out.println(label + renderer.renderToString(messages[i]));
320
 
                    }
321
 
                }
322
 
            }
323
 
        }
324
 
    }
325
 
 
326
 
    public static String toShortString(IMessage message) {
327
 
        if (null == message) {
328
 
            return "null";
329
 
        }
330
 
        String m = message.getMessage();
331
 
        Throwable t = message.getThrown();
332
 
        
333
 
        return (message.getKind() + (null == m ? "" : ": " + m)
334
 
            + (null == t ? "" : ": " + LangUtil.unqualifiedClassName(t)));
335
 
    }
336
 
    
337
 
    /** @return int number of message of this kind (optionally or greater) in list */
338
 
    public static int numMessages(List messages, Kind kind, boolean orGreater) {
339
 
        if (LangUtil.isEmpty(messages)) {
340
 
            return 0;
341
 
        }
342
 
        IMessageHandler selector = makeSelector(kind, orGreater, null);
343
 
        IMessage[] result = visitMessages(messages, selector, true, false);
344
 
        return result.length;
345
 
    }
346
 
 
347
 
    
348
 
    /** 
349
 
     * Select all messages in holder except those of the same
350
 
     * kind (optionally or greater).
351
 
     * If kind is null, then all messages are rejected,
352
 
     * so an empty list is returned.
353
 
     * @return unmodifiable list of specified IMessage  
354
 
     */
355
 
    public static IMessage[] getMessagesExcept(IMessageHolder holder, 
356
 
            final IMessage.Kind kind, final boolean orGreater) { 
357
 
        if ((null == holder) || (null == kind)) {
358
 
            return new IMessage[0];
359
 
        }
360
 
        
361
 
        IMessageHandler selector = new IMessageHandler(){
362
 
            public boolean handleMessage(IMessage message) {
363
 
                IMessage.Kind test = message.getKind();
364
 
                return (!(orGreater
365
 
                        ? kind.isSameOrLessThan(test)
366
 
                        : kind == test));
367
 
            }
368
 
            public boolean isIgnoring(Kind kind) {
369
 
                return false;
370
 
            }
371
 
            public void dontIgnore(IMessage.Kind kind) {
372
 
                
373
 
            }
 
257
                print(out, messageHolder, (String) null, (IMessageRenderer) null, (IMessageHandler) null);
 
258
        }
 
259
 
 
260
        /**
 
261
         * Print all message to the print stream, starting each on a new line, with a prefix.
 
262
         * 
 
263
         * @param messageHolder
 
264
         * @param out
 
265
         * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
 
266
         */
 
267
        public static void print(PrintStream out, IMessageHolder holder, String prefix) {
 
268
                print(out, holder, prefix, (IMessageRenderer) null, (IMessageHandler) null);
 
269
        }
 
270
 
 
271
        /**
 
272
         * Print all message to the print stream, starting each on a new line, with a prefix and using a renderer.
 
273
         * 
 
274
         * @param messageHolder
 
275
         * @param out
 
276
         * @param renderer IMessageRender to render result - use MESSAGE_LINE if null
 
277
         * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
 
278
         */
 
279
        public static void print(PrintStream out, IMessageHolder holder, String prefix, IMessageRenderer renderer) {
 
280
                print(out, holder, prefix, renderer, (IMessageHandler) null);
 
281
        }
 
282
 
 
283
        /**
 
284
         * Print all message to the print stream, starting each on a new line, with a prefix and using a renderer. The first line
 
285
         * renders a summary: {prefix}MessageHolder: {summary} Each message line has the following form:
 
286
         * 
 
287
         * <pre>
 
288
         * {prefix}[{kind} {index}]: {rendering}
 
289
         * </pre>
 
290
         * 
 
291
         * (where "{index}" (length 3) is the position within the set of like-kinded messages, ignoring selector omissions. Renderers
 
292
         * are free to render multi-line output.
 
293
         * 
 
294
         * @param out the PrintStream sink - return silently if null
 
295
         * @param messageHolder the IMessageHolder with the messages to print
 
296
         * @param renderer IMessageRender to render result - use MESSAGE_ALL if null
 
297
         * @param selector IMessageHandler to select messages to render - if null, do all non-null
 
298
         */
 
299
        public static void print(PrintStream out, IMessageHolder holder, String prefix, IMessageRenderer renderer,
 
300
                        IMessageHandler selector) {
 
301
                print(out, holder, prefix, renderer, selector, true);
 
302
        }
 
303
 
 
304
        public static void print(PrintStream out, IMessageHolder holder, String prefix, IMessageRenderer renderer,
 
305
                        IMessageHandler selector, boolean printSummary) {
 
306
                if ((null == out) || (null == holder)) {
 
307
                        return;
 
308
                }
 
309
                if (null == renderer) {
 
310
                        renderer = MESSAGE_ALL;
 
311
                }
 
312
                if (null == selector) {
 
313
                        selector = PICK_ALL;
 
314
                }
 
315
                if (printSummary) {
 
316
                        out.println(prefix + "MessageHolder: " + MessageUtil.renderCounts(holder));
 
317
                }
 
318
                for (IMessage.Kind kind : IMessage.KINDS) {
 
319
                        if (!selector.isIgnoring(kind)) {
 
320
                                IMessage[] messages = holder.getMessages(kind, IMessageHolder.EQUAL);
 
321
                                for (int i = 0; i < messages.length; i++) {
 
322
                                        if (selector.handleMessage(messages[i])) {
 
323
                                                String label = (null == prefix ? "" : prefix + "[" + kind + " " + LangUtil.toSizedString(i, 3) + "]: ");
 
324
                                                out.println(label + renderer.renderToString(messages[i]));
 
325
                                        }
 
326
                                }
 
327
                        }
 
328
                }
 
329
        }
 
330
 
 
331
        public static String toShortString(IMessage message) {
 
332
                if (null == message) {
 
333
                        return "null";
 
334
                }
 
335
                String m = message.getMessage();
 
336
                Throwable t = message.getThrown();
 
337
 
 
338
                return (message.getKind() + (null == m ? "" : ": " + m) + (null == t ? "" : ": " + LangUtil.unqualifiedClassName(t)));
 
339
        }
 
340
 
 
341
        /** @return int number of message of this kind (optionally or greater) in list */
 
342
        public static int numMessages(List<IMessage> messages, Kind kind, boolean orGreater) {
 
343
                if (LangUtil.isEmpty(messages)) {
 
344
                        return 0;
 
345
                }
 
346
                IMessageHandler selector = makeSelector(kind, orGreater, null);
 
347
                IMessage[] result = visitMessages(messages, selector, true, false);
 
348
                return result.length;
 
349
        }
 
350
 
 
351
        /**
 
352
         * Select all messages in holder except those of the same kind (optionally or greater). If kind is null, then all messages are
 
353
         * rejected, so an empty list is returned.
 
354
         * 
 
355
         * @return unmodifiable list of specified IMessage
 
356
         */
 
357
        public static IMessage[] getMessagesExcept(IMessageHolder holder, final IMessage.Kind kind, final boolean orGreater) {
 
358
                if ((null == holder) || (null == kind)) {
 
359
                        return new IMessage[0];
 
360
                }
 
361
 
 
362
                IMessageHandler selector = new IMessageHandler() {
 
363
                        public boolean handleMessage(IMessage message) {
 
364
                                IMessage.Kind test = message.getKind();
 
365
                                return (!(orGreater ? kind.isSameOrLessThan(test) : kind == test));
 
366
                        }
 
367
 
 
368
                        public boolean isIgnoring(Kind kind) {
 
369
                                return false;
 
370
                        }
 
371
 
 
372
                        public void dontIgnore(IMessage.Kind kind) {
 
373
 
 
374
                        }
 
375
 
374
376
                        public void ignore(Kind kind) {
375
377
                        }
376
 
        };
377
 
        return visitMessages(holder, selector, true, false);
378
 
    }
 
378
                };
 
379
                return visitMessages(holder, selector, true, false);
 
380
        }
379
381
 
380
 
    /** @return unmodifiable list of IMessage complying with parameters */
381
 
    public static List getMessages(IMessageHolder holder, 
382
 
            IMessage.Kind kind, boolean orGreater, String infix) { // XXX untested
383
 
        if (null == holder) {
384
 
            return Collections.EMPTY_LIST;
385
 
        }
386
 
        if ((null == kind) && LangUtil.isEmpty(infix)) {
387
 
            return holder.getUnmodifiableListView();
388
 
        }
389
 
        IMessageHandler selector = makeSelector(kind, orGreater, infix);
390
 
        IMessage[] messages = visitMessages(holder, selector, true, false);
391
 
        if (LangUtil.isEmpty(messages)) {
392
 
            return Collections.EMPTY_LIST;
393
 
        }
394
 
        return Collections.unmodifiableList(Arrays.asList(messages));
395
 
    }
 
382
        /** @return unmodifiable list of IMessage complying with parameters */
 
383
        public static List<IMessage> getMessages(IMessageHolder holder, IMessage.Kind kind, boolean orGreater, String infix) {
 
384
                if (null == holder) {
 
385
                        return Collections.emptyList();
 
386
                }
 
387
                if ((null == kind) && LangUtil.isEmpty(infix)) {
 
388
                        return holder.getUnmodifiableListView();
 
389
                }
 
390
                IMessageHandler selector = makeSelector(kind, orGreater, infix);
 
391
                IMessage[] messages = visitMessages(holder, selector, true, false);
 
392
                if (LangUtil.isEmpty(messages)) {
 
393
                        return Collections.emptyList();
 
394
                }
 
395
                return Collections.unmodifiableList(Arrays.asList(messages));
 
396
        }
396
397
 
397
398
        /**
398
399
         * Extract messages of type kind from the input list.
399
 
     * 
 
400
         * 
400
401
         * @param messages if null, return EMPTY_LIST
401
402
         * @param kind if null, return messages
402
 
     * @see MessageHandler#getMessages(Kind)
 
403
         * @see MessageHandler#getMessages(Kind)
403
404
         */
404
 
        public static List getMessages(List messages, IMessage.Kind kind) {
405
 
       if (null == messages) {
406
 
            return Collections.EMPTY_LIST;
407
 
       }
408
 
       if (null == kind) {
409
 
            return messages;
410
 
       }
411
 
        ArrayList result = new ArrayList();
412
 
        for (Iterator iter = messages.iterator(); iter.hasNext();) {
413
 
            IMessage element = (IMessage) iter.next();
414
 
            if (kind == element.getKind()) {
415
 
                result.add(element);
416
 
            }
417
 
        }
418
 
        if (0 == result.size()) {
419
 
            return Collections.EMPTY_LIST;
420
 
        }
421
 
        return result;
 
405
        public static List<IMessage> getMessages(List<IMessage> messages, IMessage.Kind kind) {
 
406
                if (null == messages) {
 
407
                        return Collections.emptyList();
 
408
                }
 
409
                if (null == kind) {
 
410
                        return messages;
 
411
                }
 
412
                ArrayList<IMessage> result = new ArrayList<IMessage>();
 
413
                for (IMessage message : messages) {
 
414
                        if (kind == message.getKind()) {
 
415
                                result.add(message);
 
416
                        }
 
417
                }
 
418
                if (0 == result.size()) {
 
419
                        return Collections.emptyList();
 
420
                }
 
421
                return result;
422
422
        }
423
423
 
424
424
        /**
425
425
         * Map to the kind of messages associated with this string key.
 
426
         * 
426
427
         * @param kind the String representing the kind of message (IMessage.Kind.toString())
427
428
         * @return Kind the associated IMessage.Kind, or null if not found
428
429
         */
429
430
        public static IMessage.Kind getKind(String kind) {
430
 
        if (null != kind) {
431
 
            kind = kind.toLowerCase();
432
 
           for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
433
 
                                IMessage.Kind k = (IMessage.Kind) iter.next();
434
 
                        if (kind.equals(k.toString())) {
435
 
                    return k;
436
 
                }
437
 
                }
438
 
        }
 
431
                if (null != kind) {
 
432
                        kind = kind.toLowerCase();
 
433
                        for (IMessage.Kind k : IMessage.KINDS) {
 
434
                                if (kind.equals(k.toString())) {
 
435
                                        return k;
 
436
                                }
 
437
                        }
 
438
                }
439
439
                return null;
440
440
        }
441
 
    
442
 
    /** 
443
 
     * Run visitor over the set of messages in holder,
444
 
     * optionally accumulating those accepted by the visitor
445
 
     */
446
 
    public static IMessage[] visitMessages(IMessageHolder holder, 
447
 
            IMessageHandler visitor, boolean accumulate, boolean abortOnFail) {
448
 
        if (null == holder) {
449
 
            return IMessage.RA_IMessage;
450
 
        } else {
451
 
            return visitMessages(holder.getUnmodifiableListView(), visitor, accumulate, abortOnFail);
452
 
        }
453
 
    }
454
 
 
455
 
    /** 
456
 
     * Run visitor over the set of messages in holder,
457
 
     * optionally accumulating those accepted by the visitor
458
 
     */
459
 
    public static IMessage[] visitMessages(IMessage[] messages, 
460
 
            IMessageHandler visitor, boolean accumulate, boolean abortOnFail) {
461
 
        if (LangUtil.isEmpty(messages)) {
462
 
            return IMessage.RA_IMessage;
463
 
        } else {
464
 
            return visitMessages(Arrays.asList(messages), visitor, accumulate, abortOnFail);
465
 
        }
466
 
    }
467
 
    
468
 
    /** 
469
 
     * Run visitor over a collection of messages,
470
 
     * optionally accumulating those accepted by the visitor
471
 
     * @param messages if null or empty, return IMessage.RA_IMessage
472
 
     * @param visitor run visitor.handleMessage(message) on each
473
 
     *         message - if null and messages not empty, IllegalArgumentException
474
 
     * @param accumulate if true, then return accepted IMessage[]
475
 
     * @param abortOnFail if true and visitor returns false, stop visiting
476
 
     * @return IMessage.RA_IMessage if collection is empty, if not accumulate,
477
 
     *          or if visitor accepted no IMessage, 
478
 
     *          or IMessage[] of accepted messages otherwise
479
 
     * @throws IllegalArgumentException if any in collection are not instanceof IMessage
480
 
     */
481
 
    public static IMessage[] visitMessages(Collection /*IMessage*/ messages, 
482
 
            IMessageHandler visitor, final boolean accumulate, final boolean abortOnFail) {
483
 
        if (LangUtil.isEmpty(messages)) {
484
 
            return IMessage.RA_IMessage;
485
 
        }        
486
 
        LangUtil.throwIaxIfNull(visitor, "visitor");
487
 
        ArrayList result = (accumulate ? new ArrayList() : null);
488
 
        for (Iterator iter = messages.iterator(); iter.hasNext();) {
489
 
                        Object o = iter.next();
490
 
            LangUtil.throwIaxIfFalse(o instanceof IMessage, "expected IMessage, got " + o);
491
 
            IMessage m = (IMessage) o;
492
 
            if (visitor.handleMessage(m)) {
493
 
                if (accumulate) {
494
 
                    result.add(m);
495
 
                }
496
 
            } else if (abortOnFail) {
497
 
                break;
498
 
            }                   
499
 
                }
500
 
        if (!accumulate || (0 == result.size())) {
501
 
            return IMessage.RA_IMessage;
502
 
        } else {
503
 
            return (IMessage[]) result.toArray(IMessage.RA_IMessage);
504
 
        }
505
 
    }
506
 
    
507
 
    /** 
508
 
     * Make an IMessageHandler that handles IMessage if they have the right kind
509
 
     * (or greater) and contain some infix String.
510
 
     * @param kind the IMessage.Kind required of the message
511
 
     * @param orGreater if true, also accept messages with greater kinds, as
512
 
     *         defined by IMessage.Kind.COMPARATOR
513
 
     * @param infix the String text to require in the message - may be null or empty
514
 
     *         to accept any message with the specified kind.
515
 
     * @return IMessageHandler selector that works to param specs
516
 
     */
517
 
    public static IMessageHandler makeSelector(IMessage.Kind kind, boolean orGreater, String infix) {
518
 
        if (!orGreater && LangUtil.isEmpty(infix)) {
519
 
            if (kind == IMessage.ABORT) {
520
 
                return PICK_ABORT;
521
 
            } else if (kind == IMessage.DEBUG) {
522
 
                return PICK_DEBUG;
523
 
            } else if (kind == IMessage.DEBUG) {
524
 
                return PICK_DEBUG;
525
 
            } else if (kind == IMessage.ERROR) {
526
 
                return PICK_ERROR;
527
 
            } else if (kind == IMessage.FAIL) {
528
 
                return PICK_FAIL;
529
 
            } else if (kind == IMessage.INFO) {
530
 
                return PICK_INFO;
531
 
            } else if (kind == IMessage.WARNING) {
532
 
                return PICK_WARNING;
533
 
            }
534
 
        }
535
 
        return new KindSelector(kind, orGreater, infix);        
536
 
    }
537
 
    
538
 
    // ------------------ visitors to select messages
539
 
    public static final IMessageHandler PICK_ALL = new KindSelector((IMessage.Kind) null);
540
 
    public static final IMessageHandler PICK_ABORT = new KindSelector(IMessage.ABORT);
541
 
    public static final IMessageHandler PICK_DEBUG = new KindSelector(IMessage.DEBUG);
542
 
    public static final IMessageHandler PICK_ERROR = new KindSelector(IMessage.ERROR);
543
 
    public static final IMessageHandler PICK_FAIL = new KindSelector(IMessage.FAIL);
544
 
    public static final IMessageHandler PICK_INFO = new KindSelector(IMessage.INFO);
545
 
    public static final IMessageHandler PICK_WARNING = new KindSelector(IMessage.WARNING);
546
 
    public static final IMessageHandler PICK_ABORT_PLUS = new KindSelector(IMessage.ABORT, true);
547
 
    public static final IMessageHandler PICK_DEBUG_PLUS = new KindSelector(IMessage.DEBUG, true);
548
 
    public static final IMessageHandler PICK_ERROR_PLUS = new KindSelector(IMessage.ERROR, true);
549
 
    public static final IMessageHandler PICK_FAIL_PLUS = new KindSelector(IMessage.FAIL, true);
550
 
    public static final IMessageHandler PICK_INFO_PLUS = new KindSelector(IMessage.INFO, true);
551
 
    public static final IMessageHandler PICK_WARNING_PLUS = new KindSelector(IMessage.WARNING, true);
552
 
 
553
 
 
554
 
    /** implementation for PICK_... constants */
555
 
    private static class KindSelector implements IMessageHandler {
556
 
        final IMessage.Kind sought;
557
 
        final boolean floor;
558
 
        final String infix;
559
 
    
560
 
        KindSelector(IMessage.Kind sought) {
561
 
            this(sought, false);
562
 
        }
563
 
    
564
 
        KindSelector(IMessage.Kind sought, boolean floor) {
565
 
            this(sought, floor, null);
566
 
        }
567
 
    
568
 
        KindSelector(IMessage.Kind sought, boolean floor, String infix) {
569
 
            this.sought = sought;
570
 
            this.floor = floor;
571
 
            this.infix = (LangUtil.isEmpty(infix) ? null : infix);
572
 
        }
573
 
        
574
 
        /** @return false if this message is null,
575
 
         * of true if we seek any kind (null)
576
 
         * or if this has the exact kind we seek
577
 
         * and this has any text sought
578
 
         */
579
 
        public boolean handleMessage(IMessage message) {
580
 
            return ((null != message) && !isIgnoring(message.getKind())
581
 
                && textIn(message));
582
 
        }
583
 
    
584
 
        /** @return true if handleMessage would return false for a message of this kind */
585
 
        public boolean isIgnoring(IMessage.Kind kind) {            
586
 
            if (!floor) {
587
 
                return ((null != sought) && (sought != kind));
588
 
            } else if (null == sought) {
589
 
                return false;
590
 
            } else {
591
 
                return (0 < IMessage.Kind.COMPARATOR.compare(sought, kind));
592
 
            }
593
 
        }
594
 
 
595
 
        public void dontIgnore(IMessage.Kind kind) {
596
 
            
597
 
        }
598
 
 
599
 
        private boolean textIn(IMessage message) {
600
 
            if (null == infix) {
601
 
                return true;
602
 
            }
603
 
            String text = message.getMessage();
604
 
            return (text.indexOf(infix)!=-1);
605
 
        }
 
441
 
 
442
        /**
 
443
         * Run visitor over the set of messages in holder, optionally accumulating those accepted by the visitor
 
444
         */
 
445
        public static IMessage[] visitMessages(IMessageHolder holder, IMessageHandler visitor, boolean accumulate, boolean abortOnFail) {
 
446
                if (null == holder) {
 
447
                        return IMessage.RA_IMessage;
 
448
                } else {
 
449
                        return visitMessages(holder.getUnmodifiableListView(), visitor, accumulate, abortOnFail);
 
450
                }
 
451
        }
 
452
 
 
453
        /**
 
454
         * Run visitor over the set of messages in holder, optionally accumulating those accepted by the visitor
 
455
         */
 
456
        public static IMessage[] visitMessages(IMessage[] messages, IMessageHandler visitor, boolean accumulate, boolean abortOnFail) {
 
457
                if (LangUtil.isEmpty(messages)) {
 
458
                        return IMessage.RA_IMessage;
 
459
                } else {
 
460
                        return visitMessages(Arrays.asList(messages), visitor, accumulate, abortOnFail);
 
461
                }
 
462
        }
 
463
 
 
464
        /**
 
465
         * Run visitor over a collection of messages, optionally accumulating those accepted by the visitor
 
466
         * 
 
467
         * @param messages if null or empty, return IMessage.RA_IMessage
 
468
         * @param visitor run visitor.handleMessage(message) on each message - if null and messages not empty, IllegalArgumentException
 
469
         * @param accumulate if true, then return accepted IMessage[]
 
470
         * @param abortOnFail if true and visitor returns false, stop visiting
 
471
         * @return IMessage.RA_IMessage if collection is empty, if not accumulate, or if visitor accepted no IMessage, or IMessage[] of
 
472
         *         accepted messages otherwise
 
473
         * @throws IllegalArgumentException if any in collection are not instanceof IMessage
 
474
         */
 
475
        public static IMessage[] visitMessages(Collection<IMessage> messages, IMessageHandler visitor, final boolean accumulate,
 
476
                        final boolean abortOnFail) {
 
477
                if (LangUtil.isEmpty(messages)) {
 
478
                        return IMessage.RA_IMessage;
 
479
                }
 
480
                LangUtil.throwIaxIfNull(visitor, "visitor");
 
481
                ArrayList<IMessage> result = (accumulate ? new ArrayList<IMessage>() : null);
 
482
                for (IMessage m : messages) {
 
483
                        if (visitor.handleMessage(m)) {
 
484
                                if (accumulate) {
 
485
                                        result.add(m);
 
486
                                }
 
487
                        } else if (abortOnFail) {
 
488
                                break;
 
489
                        }
 
490
                }
 
491
                if (!accumulate || (0 == result.size())) {
 
492
                        return IMessage.RA_IMessage;
 
493
                } else {
 
494
                        return result.toArray(IMessage.RA_IMessage);
 
495
                }
 
496
        }
 
497
 
 
498
        /**
 
499
         * Make an IMessageHandler that handles IMessage if they have the right kind (or greater) and contain some infix String.
 
500
         * 
 
501
         * @param kind the IMessage.Kind required of the message
 
502
         * @param orGreater if true, also accept messages with greater kinds, as defined by IMessage.Kind.COMPARATOR
 
503
         * @param infix the String text to require in the message - may be null or empty to accept any message with the specified kind.
 
504
         * @return IMessageHandler selector that works to param specs
 
505
         */
 
506
        public static IMessageHandler makeSelector(IMessage.Kind kind, boolean orGreater, String infix) {
 
507
                if (!orGreater && LangUtil.isEmpty(infix)) {
 
508
                        if (kind == IMessage.ABORT) {
 
509
                                return PICK_ABORT;
 
510
                        } else if (kind == IMessage.DEBUG) {
 
511
                                return PICK_DEBUG;
 
512
                        } else if (kind == IMessage.DEBUG) {
 
513
                                return PICK_DEBUG;
 
514
                        } else if (kind == IMessage.ERROR) {
 
515
                                return PICK_ERROR;
 
516
                        } else if (kind == IMessage.FAIL) {
 
517
                                return PICK_FAIL;
 
518
                        } else if (kind == IMessage.INFO) {
 
519
                                return PICK_INFO;
 
520
                        } else if (kind == IMessage.WARNING) {
 
521
                                return PICK_WARNING;
 
522
                        }
 
523
                }
 
524
                return new KindSelector(kind, orGreater, infix);
 
525
        }
 
526
 
 
527
        // ------------------ visitors to select messages
 
528
        public static final IMessageHandler PICK_ALL = new KindSelector((IMessage.Kind) null);
 
529
        public static final IMessageHandler PICK_ABORT = new KindSelector(IMessage.ABORT);
 
530
        public static final IMessageHandler PICK_DEBUG = new KindSelector(IMessage.DEBUG);
 
531
        public static final IMessageHandler PICK_ERROR = new KindSelector(IMessage.ERROR);
 
532
        public static final IMessageHandler PICK_FAIL = new KindSelector(IMessage.FAIL);
 
533
        public static final IMessageHandler PICK_INFO = new KindSelector(IMessage.INFO);
 
534
        public static final IMessageHandler PICK_WARNING = new KindSelector(IMessage.WARNING);
 
535
        public static final IMessageHandler PICK_ABORT_PLUS = new KindSelector(IMessage.ABORT, true);
 
536
        public static final IMessageHandler PICK_DEBUG_PLUS = new KindSelector(IMessage.DEBUG, true);
 
537
        public static final IMessageHandler PICK_ERROR_PLUS = new KindSelector(IMessage.ERROR, true);
 
538
        public static final IMessageHandler PICK_FAIL_PLUS = new KindSelector(IMessage.FAIL, true);
 
539
        public static final IMessageHandler PICK_INFO_PLUS = new KindSelector(IMessage.INFO, true);
 
540
        public static final IMessageHandler PICK_WARNING_PLUS = new KindSelector(IMessage.WARNING, true);
 
541
 
 
542
        /** implementation for PICK_... constants */
 
543
        private static class KindSelector implements IMessageHandler {
 
544
                final IMessage.Kind sought;
 
545
                final boolean floor;
 
546
                final String infix;
 
547
 
 
548
                KindSelector(IMessage.Kind sought) {
 
549
                        this(sought, false);
 
550
                }
 
551
 
 
552
                KindSelector(IMessage.Kind sought, boolean floor) {
 
553
                        this(sought, floor, null);
 
554
                }
 
555
 
 
556
                KindSelector(IMessage.Kind sought, boolean floor, String infix) {
 
557
                        this.sought = sought;
 
558
                        this.floor = floor;
 
559
                        this.infix = (LangUtil.isEmpty(infix) ? null : infix);
 
560
                }
 
561
 
 
562
                /**
 
563
                 * @return false if this message is null, of true if we seek any kind (null) or if this has the exact kind we seek and this
 
564
                 *         has any text sought
 
565
                 */
 
566
                public boolean handleMessage(IMessage message) {
 
567
                        return ((null != message) && !isIgnoring(message.getKind()) && textIn(message));
 
568
                }
 
569
 
 
570
                /** @return true if handleMessage would return false for a message of this kind */
 
571
                public boolean isIgnoring(IMessage.Kind kind) {
 
572
                        if (!floor) {
 
573
                                return ((null != sought) && (sought != kind));
 
574
                        } else if (null == sought) {
 
575
                                return false;
 
576
                        } else {
 
577
                                return (0 < IMessage.Kind.COMPARATOR.compare(sought, kind));
 
578
                        }
 
579
                }
 
580
 
 
581
                public void dontIgnore(IMessage.Kind kind) {
 
582
 
 
583
                }
 
584
 
 
585
                private boolean textIn(IMessage message) {
 
586
                        if (null == infix) {
 
587
                                return true;
 
588
                        }
 
589
                        String text = message.getMessage();
 
590
                        return (text.indexOf(infix) != -1);
 
591
                }
606
592
 
607
593
                public void ignore(Kind kind) {
608
594
                }
609
 
    }
610
 
 
611
 
    // ------------------ components to render  messages
612
 
    /** parameterize rendering behavior for messages */
613
 
    public static interface IMessageRenderer {
614
 
        String renderToString(IMessage message);
615
 
    }
616
 
 
617
 
 
618
 
    /** render message more verbosely if it is worse */
619
 
    public static final IMessageRenderer MESSAGE_SCALED = new IMessageRenderer() {
620
 
        public String toString() { return "MESSAGE_SCALED"; }
621
 
        public String renderToString(IMessage message) {
622
 
            if (null == message) {
623
 
                return "((IMessage) null)";
624
 
            }
625
 
            IMessage.Kind kind = message.getKind();
626
 
            int level = 3;
627
 
            if ((kind == IMessage.ABORT) || (kind == IMessage.FAIL)) {
628
 
                level = 1;
629
 
            } else if ((kind == IMessage.ERROR) || (kind == IMessage.WARNING)) {
630
 
                level = 2;
631
 
            } else {
632
 
                level = 3;
633
 
            }
634
 
            String result = null;
635
 
            switch (level) {
636
 
                case (1) :
637
 
                    result = MESSAGE_TOSTRING.renderToString(message);
638
 
                break;
639
 
                case (2) :
640
 
                    result = MESSAGE_LINE.renderToString(message);
641
 
                break;
642
 
                case (3) :
643
 
                    result = MESSAGE_SHORT.renderToString(message);
644
 
                break;
645
 
            }
646
 
            Throwable thrown = message.getThrown();
647
 
            if (null != thrown) {
648
 
                if (level == 3) {
649
 
                    result += "Thrown: \n" + LangUtil.renderExceptionShort(thrown);
650
 
                } else {
651
 
                    result += "Thrown: \n" + LangUtil.renderException(thrown);
652
 
                }
653
 
            }
654
 
                    
655
 
            return result;
656
 
        }
657
 
    };
658
 
 
659
 
    /** render message as label, i.e., less than 33 char */
660
 
    public static final IMessageRenderer MESSAGE_LABEL = new IMessageRenderer() {
661
 
        public String toString() { return "MESSAGE_LABEL"; }
662
 
        public String renderToString(IMessage message) {
663
 
            if (null == message) {
664
 
                return "((IMessage) null)";
665
 
            }
666
 
            return renderMessageLine(message, 5, 5, 32);
667
 
        }
668
 
    };
669
 
 
670
 
    /** render message as label, i.e., less than 33 char, with no source location */
671
 
    public static final IMessageRenderer MESSAGE_LABEL_NOLOC = new IMessageRenderer() {
672
 
        public String toString() { return "MESSAGE_LABEL_NOLOC"; }
673
 
        public String renderToString(IMessage message) {
674
 
            if (null == message) {
675
 
                return "((IMessage) null)";
676
 
            }
677
 
            return renderMessageLine(message, 10, 0, 32);
678
 
        }
679
 
    };
680
 
 
681
 
    /** render message as line, i.e., less than 75 char, no internal line sep */
682
 
    public static final IMessageRenderer MESSAGE_LINE = new IMessageRenderer() {
683
 
        public String toString() { return "MESSAGE_LINE"; }
684
 
        public String renderToString(IMessage message) {
685
 
            if (null == message) {
686
 
                return "((IMessage) null)";
687
 
            }
688
 
            return renderMessageLine(message, 8, 2, 74);
689
 
        }
690
 
    };
691
 
    
692
 
    /** render message as line, i.e., less than 75 char, no internal line sep, 
693
 
     * trying to trim text as needed to end with a full source location */
694
 
    public static final IMessageRenderer MESSAGE_LINE_FORCE_LOC = new IMessageRenderer() {
695
 
        public String toString() { return "MESSAGE_LINE_FORCE_LOC"; }
696
 
        public String renderToString(IMessage message) {
697
 
            if (null == message) {
698
 
                return "((IMessage) null)";
699
 
            }
700
 
            return renderMessageLine(message, 2, 40, 74);
701
 
        }
702
 
    };
703
 
    
704
 
    /** render message without restriction, up to 10K, including throwable */
705
 
    public static final IMessageRenderer MESSAGE_ALL = new IMessageRenderer() {
706
 
        public String toString() { return "MESSAGE_ALL"; }
707
 
        public String renderToString(IMessage message) {
708
 
            return renderMessage(message);
709
 
        }
710
 
    };
711
 
 
712
 
//    /** render message without restriction, up to 10K, including (but eliding) throwable */
713
 
//    public static final IMessageRenderer MESSAGE_ALL_ELIDED= new IMessageRenderer() {
714
 
//        public String toString() { return "MESSAGE_ALL_ELIDED"; }
715
 
//        public String renderToString(IMessage message) {
716
 
//            return renderMessage(message, true);
717
 
//        }
718
 
//    };
719
 
 
720
 
    /** render message without restriction, except any Throwable thrown */
721
 
    public static final IMessageRenderer MESSAGE_MOST = new IMessageRenderer() {
722
 
        public String toString() { return "MESSAGE_MOST"; }
723
 
        public String renderToString(IMessage message) {
724
 
            if (null == message) {
725
 
                return "((IMessage) null)";
726
 
            }
727
 
            return renderMessageLine(message, 1, 1, 10000);
728
 
        }
729
 
    };
730
 
 
731
 
    /** render message as wide line, i.e., less than 256 char, no internal line sep,
732
 
     *  except any Throwable thrown  
733
 
     */
734
 
    public static final IMessageRenderer MESSAGE_WIDELINE = new IMessageRenderer() {
735
 
        public String toString() { return "MESSAGE_WIDELINE"; }
736
 
        public String renderToString(IMessage message) {
737
 
            if (null == message) {
738
 
                return "((IMessage) null)";
739
 
            }
740
 
            return renderMessageLine(message, 8, 2, 255); // XXX revert to 256
741
 
        }
742
 
    };
743
 
    /** render message using its toString() or "((IMessage) null)" */
744
 
    public static final IMessageRenderer MESSAGE_TOSTRING = new IMessageRenderer() {
745
 
        public String toString() { return "MESSAGE_TOSTRING"; }
746
 
        public String renderToString(IMessage message) {
747
 
            if (null == message) {
748
 
                return "((IMessage) null)";
749
 
            }
750
 
            return message.toString();
751
 
        }
752
 
    };
753
 
 
754
 
    /** render message using toShortString(IMessage)" */
755
 
    public static final IMessageRenderer MESSAGE_SHORT = new IMessageRenderer() {
756
 
        public String toString() { return "MESSAGE_SHORT"; }
757
 
        public String renderToString(IMessage message) {
758
 
            return toShortString(message);
759
 
        }
760
 
    };
761
 
 
762
 
    /** 
763
 
     * This renders IMessage as String, ignoring empty elements
764
 
     * and eliding any thrown stack traces.
765
 
     * @return "((IMessage) null)" if null or String rendering otherwise,
766
 
     *           including everything (esp. throwable stack trace)
767
 
     * @see renderSourceLocation(ISourceLocation loc)
768
 
     */
769
 
    public static String renderMessage(IMessage message) {
770
 
        return renderMessage(message, true);
771
 
    }
772
 
    
773
 
    /** 
774
 
     * This renders IMessage as String, ignoring empty elements
775
 
     * and eliding any thrown.
776
 
     * @return "((IMessage) null)" if null or String rendering otherwise,
777
 
     *           including everything (esp. throwable stack trace)
778
 
     * @see renderSourceLocation(ISourceLocation loc)
779
 
     */
780
 
    public static String renderMessage(IMessage message, boolean elide) {
781
 
        if (null == message) {
782
 
            return "((IMessage) null)";
783
 
        }
784
 
       
785
 
        ISourceLocation loc = message.getSourceLocation();
786
 
        String locString = (null == loc ? "" : " at " + loc);
787
 
        
788
 
        String result = message.getKind() + locString + " " + message.getMessage();
789
 
      
790
 
        Throwable thrown = message.getThrown();
791
 
        if (thrown != null) {
792
 
            result += " -- " + LangUtil.renderExceptionShort(thrown);  
793
 
            result += "\n" + LangUtil.renderException(thrown, elide);         
794
 
        }
795
 
        
796
 
        if (message.getExtraSourceLocations().isEmpty()) {
797
 
            return result;    
798
 
        }
799
 
        else {
800
 
            return addExtraSourceLocations(message, result);    
801
 
        }
802
 
    }
803
 
 
804
 
        public static String addExtraSourceLocations(
805
 
                IMessage message,
806
 
                String baseMessage)
807
 
        {
 
595
        }
 
596
 
 
597
        // ------------------ components to render messages
 
598
        /** parameterize rendering behavior for messages */
 
599
        public static interface IMessageRenderer {
 
600
                String renderToString(IMessage message);
 
601
        }
 
602
 
 
603
        /** render message more verbosely if it is worse */
 
604
        public static final IMessageRenderer MESSAGE_SCALED = new IMessageRenderer() {
 
605
                public String toString() {
 
606
                        return "MESSAGE_SCALED";
 
607
                }
 
608
 
 
609
                public String renderToString(IMessage message) {
 
610
                        if (null == message) {
 
611
                                return "((IMessage) null)";
 
612
                        }
 
613
                        IMessage.Kind kind = message.getKind();
 
614
                        int level = 3;
 
615
                        if ((kind == IMessage.ABORT) || (kind == IMessage.FAIL)) {
 
616
                                level = 1;
 
617
                        } else if ((kind == IMessage.ERROR) || (kind == IMessage.WARNING)) {
 
618
                                level = 2;
 
619
                        } else {
 
620
                                level = 3;
 
621
                        }
 
622
                        String result = null;
 
623
                        switch (level) {
 
624
                        case (1):
 
625
                                result = MESSAGE_TOSTRING.renderToString(message);
 
626
                                break;
 
627
                        case (2):
 
628
                                result = MESSAGE_LINE.renderToString(message);
 
629
                                break;
 
630
                        case (3):
 
631
                                result = MESSAGE_SHORT.renderToString(message);
 
632
                                break;
 
633
                        }
 
634
                        Throwable thrown = message.getThrown();
 
635
                        if (null != thrown) {
 
636
                                if (level == 3) {
 
637
                                        result += "Thrown: \n" + LangUtil.renderExceptionShort(thrown);
 
638
                                } else {
 
639
                                        result += "Thrown: \n" + LangUtil.renderException(thrown);
 
640
                                }
 
641
                        }
 
642
 
 
643
                        return result;
 
644
                }
 
645
        };
 
646
 
 
647
        /** render message as label, i.e., less than 33 char */
 
648
        public static final IMessageRenderer MESSAGE_LABEL = new IMessageRenderer() {
 
649
                public String toString() {
 
650
                        return "MESSAGE_LABEL";
 
651
                }
 
652
 
 
653
                public String renderToString(IMessage message) {
 
654
                        if (null == message) {
 
655
                                return "((IMessage) null)";
 
656
                        }
 
657
                        return renderMessageLine(message, 5, 5, 32);
 
658
                }
 
659
        };
 
660
 
 
661
        /** render message as label, i.e., less than 33 char, with no source location */
 
662
        public static final IMessageRenderer MESSAGE_LABEL_NOLOC = new IMessageRenderer() {
 
663
                public String toString() {
 
664
                        return "MESSAGE_LABEL_NOLOC";
 
665
                }
 
666
 
 
667
                public String renderToString(IMessage message) {
 
668
                        if (null == message) {
 
669
                                return "((IMessage) null)";
 
670
                        }
 
671
                        return renderMessageLine(message, 10, 0, 32);
 
672
                }
 
673
        };
 
674
 
 
675
        /** render message as line, i.e., less than 75 char, no internal line sep */
 
676
        public static final IMessageRenderer MESSAGE_LINE = new IMessageRenderer() {
 
677
                public String toString() {
 
678
                        return "MESSAGE_LINE";
 
679
                }
 
680
 
 
681
                public String renderToString(IMessage message) {
 
682
                        if (null == message) {
 
683
                                return "((IMessage) null)";
 
684
                        }
 
685
                        return renderMessageLine(message, 8, 2, 74);
 
686
                }
 
687
        };
 
688
 
 
689
        /**
 
690
         * render message as line, i.e., less than 75 char, no internal line sep, trying to trim text as needed to end with a full
 
691
         * source location
 
692
         */
 
693
        public static final IMessageRenderer MESSAGE_LINE_FORCE_LOC = new IMessageRenderer() {
 
694
                public String toString() {
 
695
                        return "MESSAGE_LINE_FORCE_LOC";
 
696
                }
 
697
 
 
698
                public String renderToString(IMessage message) {
 
699
                        if (null == message) {
 
700
                                return "((IMessage) null)";
 
701
                        }
 
702
                        return renderMessageLine(message, 2, 40, 74);
 
703
                }
 
704
        };
 
705
 
 
706
        /** render message without restriction, up to 10K, including throwable */
 
707
        public static final IMessageRenderer MESSAGE_ALL = new IMessageRenderer() {
 
708
                public String toString() {
 
709
                        return "MESSAGE_ALL";
 
710
                }
 
711
 
 
712
                public String renderToString(IMessage message) {
 
713
                        return renderMessage(message);
 
714
                }
 
715
        };
 
716
 
 
717
        // /** render message without restriction, up to 10K, including (but eliding) throwable */
 
718
        // public static final IMessageRenderer MESSAGE_ALL_ELIDED= new IMessageRenderer() {
 
719
        // public String toString() { return "MESSAGE_ALL_ELIDED"; }
 
720
        // public String renderToString(IMessage message) {
 
721
        // return renderMessage(message, true);
 
722
        // }
 
723
        // };
 
724
 
 
725
        /** render message without restriction, except any Throwable thrown */
 
726
        public static final IMessageRenderer MESSAGE_MOST = new IMessageRenderer() {
 
727
                public String toString() {
 
728
                        return "MESSAGE_MOST";
 
729
                }
 
730
 
 
731
                public String renderToString(IMessage message) {
 
732
                        if (null == message) {
 
733
                                return "((IMessage) null)";
 
734
                        }
 
735
                        return renderMessageLine(message, 1, 1, 10000);
 
736
                }
 
737
        };
 
738
 
 
739
        /**
 
740
         * render message as wide line, i.e., less than 256 char, no internal line sep, except any Throwable thrown
 
741
         */
 
742
        public static final IMessageRenderer MESSAGE_WIDELINE = new IMessageRenderer() {
 
743
                public String toString() {
 
744
                        return "MESSAGE_WIDELINE";
 
745
                }
 
746
 
 
747
                public String renderToString(IMessage message) {
 
748
                        if (null == message) {
 
749
                                return "((IMessage) null)";
 
750
                        }
 
751
                        return renderMessageLine(message, 8, 2, 255); // XXX revert to 256
 
752
                }
 
753
        };
 
754
        /** render message using its toString() or "((IMessage) null)" */
 
755
        public static final IMessageRenderer MESSAGE_TOSTRING = new IMessageRenderer() {
 
756
                public String toString() {
 
757
                        return "MESSAGE_TOSTRING";
 
758
                }
 
759
 
 
760
                public String renderToString(IMessage message) {
 
761
                        if (null == message) {
 
762
                                return "((IMessage) null)";
 
763
                        }
 
764
                        return message.toString();
 
765
                }
 
766
        };
 
767
 
 
768
        /** render message using toShortString(IMessage)" */
 
769
        public static final IMessageRenderer MESSAGE_SHORT = new IMessageRenderer() {
 
770
                public String toString() {
 
771
                        return "MESSAGE_SHORT";
 
772
                }
 
773
 
 
774
                public String renderToString(IMessage message) {
 
775
                        return toShortString(message);
 
776
                }
 
777
        };
 
778
 
 
779
        /**
 
780
         * This renders IMessage as String, ignoring empty elements and eliding any thrown stack traces.
 
781
         * 
 
782
         * @return "((IMessage) null)" if null or String rendering otherwise, including everything (esp. throwable stack trace)
 
783
         * @see renderSourceLocation(ISourceLocation loc)
 
784
         */
 
785
        public static String renderMessage(IMessage message) {
 
786
                return renderMessage(message, true);
 
787
        }
 
788
 
 
789
        /**
 
790
         * This renders IMessage as String, ignoring empty elements and eliding any thrown.
 
791
         * 
 
792
         * @return "((IMessage) null)" if null or String rendering otherwise, including everything (esp. throwable stack trace)
 
793
         * @see renderSourceLocation(ISourceLocation loc)
 
794
         */
 
795
        public static String renderMessage(IMessage message, boolean elide) {
 
796
                if (null == message) {
 
797
                        return "((IMessage) null)";
 
798
                }
 
799
 
 
800
                ISourceLocation loc = message.getSourceLocation();
 
801
                String locString = (null == loc ? "" : " at " + loc);
 
802
 
 
803
                String result = message.getKind() + locString + " " + message.getMessage();
 
804
 
 
805
                Throwable thrown = message.getThrown();
 
806
                if (thrown != null) {
 
807
                        result += " -- " + LangUtil.renderExceptionShort(thrown);
 
808
                        result += "\n" + LangUtil.renderException(thrown, elide);
 
809
                }
 
810
 
 
811
                if (message.getExtraSourceLocations().isEmpty()) {
 
812
                        return result;
 
813
                } else {
 
814
                        return addExtraSourceLocations(message, result);
 
815
                }
 
816
        }
 
817
 
 
818
        public static String addExtraSourceLocations(IMessage message, String baseMessage) {
808
819
                StringWriter buf = new StringWriter();
809
820
                PrintWriter writer = new PrintWriter(buf);
810
821
                writer.println(baseMessage);
811
 
                for (Iterator iter = message.getExtraSourceLocations().iterator(); iter.hasNext();) {
812
 
                    ISourceLocation element = (ISourceLocation) iter.next();
813
 
                    if (element!=null) {
814
 
                        writer.print("\tsee also: " + element.toString());
815
 
                            if (iter.hasNext()) {
816
 
                                writer.println();
817
 
                            }
818
 
                    }
819
 
                }
820
 
                try { buf.close(); } 
821
 
                catch (IOException ioe) {} 
822
 
                return buf.getBuffer().toString();    
823
 
        }
824
 
    
825
 
    
826
 
    
827
 
    
828
 
    
829
 
    
830
 
    /**
831
 
     * Render ISourceLocation to String, ignoring empty elements
832
 
     * (null or ISourceLocation.NO_FILE or ISourceLocation.NO_COLUMN
833
 
     * (though implementations may return 0 from getColumn() when
834
 
     * passed NO_COLUMN as input)).
835
 
     * @return "((ISourceLocation) null)" if null or String rendering 
836
 
     *          <pre>{file:}line{:column}</pre>
837
 
     *           
838
 
     */
839
 
    public static String renderSourceLocation(ISourceLocation loc) {
840
 
        if (null == loc) {
841
 
            return "((ISourceLocation) null)";
842
 
        }
843
 
        StringBuffer sb = new StringBuffer();
844
 
        
845
 
        File sourceFile = loc.getSourceFile();
846
 
        if (sourceFile != ISourceLocation.NO_FILE) {
847
 
            sb.append(sourceFile.getPath());
848
 
            sb.append(":");
849
 
        }
850
 
        int line = loc.getLine();
851
 
        sb.append("" + line);
852
 
        
853
 
        int column = loc.getColumn();
854
 
        if (column != ISourceLocation.NO_COLUMN) {
855
 
            sb.append(":" + column);
856
 
        }
857
 
        
858
 
        return sb.toString();
859
 
    }
860
 
 
861
 
    /** 
862
 
     * Render message in a line.
863
 
     * IMessage.Kind is always printed, then any unqualified exception class,
864
 
     * then the remainder of text and location according to their relative scale,
865
 
     * all to fit in max characters or less.
866
 
     * This does not render thrown except for the unqualified class name
867
 
     * @param max the number of characters - forced to 32..10000
868
 
     * @param textScale relative proportion to spend on message and/or exception
869
 
     *         message, relative to source location - if 0, message is suppressed
870
 
     * @param locScale relative proportion to spend on source location 
871
 
     *         suppressed if 0
872
 
     * @return "((IMessage) null)" or message per spec
873
 
     */
874
 
    public static String renderMessageLine(
875
 
        IMessage message, 
876
 
        int textScale, 
877
 
        int locScale, 
878
 
        int max) {
879
 
        
880
 
        if (null == message) {
881
 
            return "((IMessage) null)";
882
 
        }
883
 
        if (max < 32) {
884
 
            max = 32;
885
 
        } else if (max > 10000) {
886
 
            max = 10000;
887
 
        }
888
 
        if (0 > textScale) {
889
 
            textScale = -textScale;
890
 
        }
891
 
        if (0 > locScale) {
892
 
            locScale = -locScale;
893
 
        }
894
 
 
895
 
        String text = message.getMessage();
896
 
        Throwable thrown = message.getThrown();
897
 
        ISourceLocation sl = message.getSourceLocation();
898
 
        IMessage.Kind kind = message.getKind();
899
 
        StringBuffer result = new StringBuffer();
900
 
        result.append(kind.toString());
901
 
        result.append(": ");
902
 
        if (null != thrown) {
903
 
            result.append(LangUtil.unqualifiedClassName(thrown) + " ");
904
 
            if ((null == text) || ("".equals(text))) {
905
 
                text = thrown.getMessage();
906
 
            } 
907
 
        }
908
 
 
909
 
        if (0 == textScale) {
910
 
            text = "";
911
 
        } else if ((null != text) && (null != thrown)) {
912
 
            // decide between message and exception text?
913
 
            String s = thrown.getMessage();
914
 
            if ((null != s) && (0 < s.length())) {
915
 
                text += " - " + s;
916
 
            }
917
 
        }
918
 
        String loc = "";
919
 
        if ((0 != locScale) && (null != sl)) {
920
 
            File f = sl.getSourceFile();
921
 
            if (f == ISourceLocation.NO_FILE) {
922
 
                f = null;
923
 
            }
924
 
            if (null != f) {
925
 
                loc = f.getName();
926
 
            }
927
 
            int line = sl.getLine();
928
 
            int col = sl.getColumn();
929
 
            int end = sl.getEndLine();
930
 
            if ((0 == line) && (0 == col) && (0 == end)) {
931
 
                // ignore numbers if default
932
 
            } else {
933
 
                loc += ":" + line + (col == 0 ? "" : ":" + col);
934
 
                if (line != end) { // XXX consider suppressing nonstandard...
935
 
                    loc += ":" + end;
936
 
                }
937
 
            }
938
 
            if (!LangUtil.isEmpty(loc)) {
939
 
                loc = "@[" + loc; // matching "]" added below after clipping
940
 
            }
941
 
        }
942
 
 
943
 
        // now budget between text and loc        
944
 
        float totalScale = locScale + textScale;
945
 
        float remainder = max - result.length() - 4;
946
 
        if ((remainder > 0) && (0 < totalScale)) {
947
 
            int textSize = (int) (remainder * textScale/totalScale);
948
 
            int locSize  = (int) (remainder * locScale/totalScale);
949
 
            // adjust for underutilization
950
 
            int extra = locSize - loc.length();
951
 
            if (0 < extra) {
952
 
                locSize = loc.length();
953
 
                textSize += extra;
954
 
            }
955
 
            extra = textSize - text.length();
956
 
            if (0 < extra) {
957
 
                textSize = text.length();
958
 
                if (locSize < loc.length()) {
959
 
                    locSize += extra;
960
 
                }
961
 
            }
962
 
            if (locSize > loc.length()) {
963
 
                locSize = loc.length();
964
 
            }
965
 
            if (textSize > text.length()) {
966
 
                textSize = text.length();
967
 
            }
968
 
            if (0 < textSize) {
969
 
                result.append(text.substring(0, textSize));
970
 
            }
971
 
            if (0 < locSize) {
972
 
                if (0 < textSize) {
973
 
                    result.append(" ");
974
 
                }
975
 
                result.append(loc.substring(0, locSize) + "]");
976
 
            }
977
 
        }
978
 
        return result.toString();
979
 
    }
 
822
                for (Iterator<ISourceLocation> iter = message.getExtraSourceLocations().iterator(); iter.hasNext();) {
 
823
                        ISourceLocation element = iter.next();
 
824
                        if (element != null) {
 
825
                                writer.print("\tsee also: " + element.toString());
 
826
                                if (iter.hasNext()) {
 
827
                                        writer.println();
 
828
                                }
 
829
                        }
 
830
                }
 
831
                try {
 
832
                        buf.close();
 
833
                } catch (IOException ioe) {
 
834
                }
 
835
                return buf.getBuffer().toString();
 
836
        }
 
837
 
 
838
        /**
 
839
         * Render ISourceLocation to String, ignoring empty elements (null or ISourceLocation.NO_FILE or ISourceLocation.NO_COLUMN
 
840
         * (though implementations may return 0 from getColumn() when passed NO_COLUMN as input)).
 
841
         * 
 
842
         * @return "((ISourceLocation) null)" if null or String rendering
 
843
         * 
 
844
         *         <pre>
 
845
         * {file:}line{:column}
 
846
         * </pre>
 
847
         * 
 
848
         */
 
849
        public static String renderSourceLocation(ISourceLocation loc) {
 
850
                if (null == loc) {
 
851
                        return "((ISourceLocation) null)";
 
852
                }
 
853
                StringBuffer sb = new StringBuffer();
 
854
 
 
855
                File sourceFile = loc.getSourceFile();
 
856
                if (sourceFile != ISourceLocation.NO_FILE) {
 
857
                        sb.append(sourceFile.getPath());
 
858
                        sb.append(":");
 
859
                }
 
860
                int line = loc.getLine();
 
861
                sb.append("" + line);
 
862
 
 
863
                int column = loc.getColumn();
 
864
                if (column != ISourceLocation.NO_COLUMN) {
 
865
                        sb.append(":" + column);
 
866
                }
 
867
 
 
868
                return sb.toString();
 
869
        }
 
870
 
 
871
        /**
 
872
         * Render message in a line. IMessage.Kind is always printed, then any unqualified exception class, then the remainder of text
 
873
         * and location according to their relative scale, all to fit in max characters or less. This does not render thrown except for
 
874
         * the unqualified class name
 
875
         * 
 
876
         * @param max the number of characters - forced to 32..10000
 
877
         * @param textScale relative proportion to spend on message and/or exception message, relative to source location - if 0,
 
878
         *        message is suppressed
 
879
         * @param locScale relative proportion to spend on source location suppressed if 0
 
880
         * @return "((IMessage) null)" or message per spec
 
881
         */
 
882
        public static String renderMessageLine(IMessage message, int textScale, int locScale, int max) {
 
883
 
 
884
                if (null == message) {
 
885
                        return "((IMessage) null)";
 
886
                }
 
887
                if (max < 32) {
 
888
                        max = 32;
 
889
                } else if (max > 10000) {
 
890
                        max = 10000;
 
891
                }
 
892
                if (0 > textScale) {
 
893
                        textScale = -textScale;
 
894
                }
 
895
                if (0 > locScale) {
 
896
                        locScale = -locScale;
 
897
                }
 
898
 
 
899
                String text = message.getMessage();
 
900
                Throwable thrown = message.getThrown();
 
901
                ISourceLocation sl = message.getSourceLocation();
 
902
                IMessage.Kind kind = message.getKind();
 
903
                StringBuffer result = new StringBuffer();
 
904
                result.append(kind.toString());
 
905
                result.append(": ");
 
906
                if (null != thrown) {
 
907
                        result.append(LangUtil.unqualifiedClassName(thrown) + " ");
 
908
                        if ((null == text) || ("".equals(text))) {
 
909
                                text = thrown.getMessage();
 
910
                        }
 
911
                }
 
912
 
 
913
                if (0 == textScale) {
 
914
                        text = "";
 
915
                } else if ((null != text) && (null != thrown)) {
 
916
                        // decide between message and exception text?
 
917
                        String s = thrown.getMessage();
 
918
                        if ((null != s) && (0 < s.length())) {
 
919
                                text += " - " + s;
 
920
                        }
 
921
                }
 
922
                String loc = "";
 
923
                if ((0 != locScale) && (null != sl)) {
 
924
                        File f = sl.getSourceFile();
 
925
                        if (f == ISourceLocation.NO_FILE) {
 
926
                                f = null;
 
927
                        }
 
928
                        if (null != f) {
 
929
                                loc = f.getName();
 
930
                        }
 
931
                        int line = sl.getLine();
 
932
                        int col = sl.getColumn();
 
933
                        int end = sl.getEndLine();
 
934
                        if ((0 == line) && (0 == col) && (0 == end)) {
 
935
                                // ignore numbers if default
 
936
                        } else {
 
937
                                loc += ":" + line + (col == 0 ? "" : ":" + col);
 
938
                                if (line != end) { // XXX consider suppressing nonstandard...
 
939
                                        loc += ":" + end;
 
940
                                }
 
941
                        }
 
942
                        if (!LangUtil.isEmpty(loc)) {
 
943
                                loc = "@[" + loc; // matching "]" added below after clipping
 
944
                        }
 
945
                }
 
946
 
 
947
                // now budget between text and loc
 
948
                float totalScale = locScale + textScale;
 
949
                float remainder = max - result.length() - 4;
 
950
                if ((remainder > 0) && (0 < totalScale)) {
 
951
                        int textSize = (int) (remainder * textScale / totalScale);
 
952
                        int locSize = (int) (remainder * locScale / totalScale);
 
953
                        // adjust for underutilization
 
954
                        int extra = locSize - loc.length();
 
955
                        if (0 < extra) {
 
956
                                locSize = loc.length();
 
957
                                textSize += extra;
 
958
                        }
 
959
                        extra = textSize - text.length();
 
960
                        if (0 < extra) {
 
961
                                textSize = text.length();
 
962
                                if (locSize < loc.length()) {
 
963
                                        locSize += extra;
 
964
                                }
 
965
                        }
 
966
                        if (locSize > loc.length()) {
 
967
                                locSize = loc.length();
 
968
                        }
 
969
                        if (textSize > text.length()) {
 
970
                                textSize = text.length();
 
971
                        }
 
972
                        if (0 < textSize) {
 
973
                                result.append(text.substring(0, textSize));
 
974
                        }
 
975
                        if (0 < locSize) {
 
976
                                if (0 < textSize) {
 
977
                                        result.append(" ");
 
978
                                }
 
979
                                result.append(loc.substring(0, locSize) + "]");
 
980
                        }
 
981
                }
 
982
                return result.toString();
 
983
        }
980
984
 
981
985
        /** @return String of the form "{(# {type}) }.." for message kinds, skipping 0 */
982
 
    public static String renderCounts(IMessageHolder holder) {
983
 
        if (0 == holder.numMessages(null, false)) {
984
 
            return "(0 messages)";
985
 
        }
986
 
        StringBuffer sb = new StringBuffer();
987
 
        for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
988
 
                        IMessage.Kind kind = (IMessage.Kind) iter.next();
 
986
        public static String renderCounts(IMessageHolder holder) {
 
987
                if (0 == holder.numMessages(null, false)) {
 
988
                        return "(0 messages)";
 
989
                }
 
990
                StringBuffer sb = new StringBuffer();
 
991
                for (IMessage.Kind kind : IMessage.KINDS) {
989
992
                        int num = holder.numMessages(kind, false);
990
 
            if (0 < num) {
991
 
                sb.append(" (" + num + " " + kind + ") ");
992
 
            }
 
993
                        if (0 < num) {
 
994
                                sb.append(" (" + num + " " + kind + ") ");
 
995
                        }
993
996
                }
994
 
        return sb.toString();
995
 
    }
996
 
    
997
 
    /** 
998
 
     * Factory for handler adapted to PrintStream 
999
 
     * XXX weak - only handles println(String) 
1000
 
     * @param handler the IMessageHandler sink for the messages generated
1001
 
     * @param kind the IMessage.Kind of message to create
1002
 
     * @param overage the OuputStream for text not captured by the handler
1003
 
     *         (if null, System.out used)
1004
 
     * @throws IllegalArgumentException if kind or handler is null
1005
 
     */
1006
 
    public static PrintStream handlerPrintStream(final IMessageHandler handler, 
1007
 
        final IMessage.Kind kind, final OutputStream overage, final String prefix) {
1008
 
        LangUtil.throwIaxIfNull(handler, "handler");
1009
 
        LangUtil.throwIaxIfNull(kind, "kind");
1010
 
        class HandlerPrintStream extends PrintStream {
1011
 
             HandlerPrintStream() {
1012
 
                super(null == overage ? System.out : overage);
1013
 
             }            
1014
 
            public void println() {
1015
 
                println("");
1016
 
            }
1017
 
            public void println(Object o) {
1018
 
                println(null == o ? "null" : o.toString());
1019
 
            }
 
997
                return sb.toString();
 
998
        }
 
999
 
 
1000
        /**
 
1001
         * Factory for handler adapted to PrintStream XXX weak - only handles println(String)
 
1002
         * 
 
1003
         * @param handler the IMessageHandler sink for the messages generated
 
1004
         * @param kind the IMessage.Kind of message to create
 
1005
         * @param overage the OuputStream for text not captured by the handler (if null, System.out used)
 
1006
         * @throws IllegalArgumentException if kind or handler is null
 
1007
         */
 
1008
        public static PrintStream handlerPrintStream(final IMessageHandler handler, final IMessage.Kind kind,
 
1009
                        final OutputStream overage, final String prefix) {
 
1010
                LangUtil.throwIaxIfNull(handler, "handler");
 
1011
                LangUtil.throwIaxIfNull(kind, "kind");
 
1012
                class HandlerPrintStream extends PrintStream {
 
1013
                        HandlerPrintStream() {
 
1014
                                super(null == overage ? System.out : overage);
 
1015
                        }
 
1016
 
 
1017
                        public void println() {
 
1018
                                println("");
 
1019
                        }
 
1020
 
 
1021
                        public void println(Object o) {
 
1022
                                println(null == o ? "null" : o.toString());
 
1023
                        }
 
1024
 
1020
1025
                        public void println(String input) {
1021
 
                String textMessage = (null == prefix ? input : prefix + input);
1022
 
                IMessage m = new Message(textMessage, kind, null, null);
1023
 
                handler.handleMessage(m);
1024
 
                        }
1025
 
        }
1026
 
        return new HandlerPrintStream();
1027
 
    }
1028
 
 
1029
 
    /** utility class */
1030
 
    private MessageUtil() {}
1031
 
 
1032
 
    /**
1033
 
     * Handle all messages in the second handler using the first
1034
 
     * @param handler the IMessageHandler sink for all messages in source
1035
 
     * @param holder the IMessageHolder source for all messages to handle
1036
 
     * @param fastFail if true, stop on first failure
1037
 
     * @return false if any sink.handleMessage(..) failed
1038
 
     */
1039
 
    public static boolean handleAll(
1040
 
        IMessageHandler sink, 
1041
 
        IMessageHolder source,
1042
 
        boolean fastFail) {
1043
 
        return handleAll(sink, source, null, true, fastFail);
1044
 
    }
1045
 
    
1046
 
    /**
1047
 
     * Handle messages in the second handler using the first
1048
 
     * @param handler the IMessageHandler sink for all messages in source
1049
 
     * @param holder the IMessageHolder source for all messages to handle
1050
 
     * @param kind the IMessage.Kind to select, if not null
1051
 
     * @param orGreater if true, also accept greater kinds
1052
 
     * @param fastFail if true, stop on first failure
1053
 
     * @return false if any sink.handleMessage(..) failed
1054
 
     */
1055
 
    public static boolean handleAll(
1056
 
        IMessageHandler sink, 
1057
 
        IMessageHolder source,
1058
 
        IMessage.Kind kind,
1059
 
        boolean orGreater, 
1060
 
        boolean fastFail) {
1061
 
        LangUtil.throwIaxIfNull(sink, "sink");
1062
 
        LangUtil.throwIaxIfNull(source, "source");
1063
 
        return handleAll(sink, source.getMessages(kind, orGreater), fastFail);
1064
 
    }
1065
 
    
1066
 
    /**
1067
 
     * Handle messages in the second handler using the first
1068
 
     * if they are NOT of this kind (optionally, or greater).
1069
 
     * If you pass null as the kind, then all messages are 
1070
 
     * ignored and this returns true.
1071
 
     * @param handler the IMessageHandler sink for all messages in source
1072
 
     * @param holder the IMessageHolder source for all messages to handle
1073
 
     * @param kind the IMessage.Kind to reject, if not null
1074
 
     * @param orGreater if true, also reject greater kinds
1075
 
     * @param fastFail if true, stop on first failure
1076
 
     * @return false if any sink.handleMessage(..) failed
1077
 
     */
1078
 
    public static boolean handleAllExcept(
1079
 
        IMessageHandler sink, 
1080
 
        IMessageHolder source,
1081
 
        IMessage.Kind kind,
1082
 
        boolean orGreater, 
1083
 
        boolean fastFail) {
1084
 
        LangUtil.throwIaxIfNull(sink, "sink");
1085
 
        LangUtil.throwIaxIfNull(source, "source");
1086
 
        if (null == kind) {
1087
 
            return true;
1088
 
        }
1089
 
        IMessage[] messages = getMessagesExcept(source, kind, orGreater);
1090
 
        return handleAll(sink, messages, fastFail);
1091
 
    }
1092
 
 
1093
 
    /**
1094
 
     * Handle messages in the sink.
1095
 
     * @param handler the IMessageHandler sink for all messages in source
1096
 
     * @param sources the IMessage[] messages to handle
1097
 
     * @param fastFail if true, stop on first failure
1098
 
     * @return false if any sink.handleMessage(..) failed
1099
 
     * @throws IllegalArgumentException if sink is null
1100
 
     */
1101
 
    public static boolean handleAll(
1102
 
        IMessageHandler sink, 
1103
 
        IMessage[] sources,
1104
 
        boolean fastFail) {
1105
 
        LangUtil.throwIaxIfNull(sink, "sink");
1106
 
        if (LangUtil.isEmpty(sources)) {
1107
 
            return true;
1108
 
        }
1109
 
        boolean result = true;
1110
 
        for (int i = 0; i < sources.length; i++) {
1111
 
            if (!sink.handleMessage(sources[i])) {
1112
 
                if (fastFail) {
1113
 
                    return false;
1114
 
                }
1115
 
                if (result) {
1116
 
                    result = false;
1117
 
                }
1118
 
            }
1119
 
        }
1120
 
        return result;
1121
 
    }
 
1026
                                String textMessage = (null == prefix ? input : prefix + input);
 
1027
                                IMessage m = new Message(textMessage, kind, null, null);
 
1028
                                handler.handleMessage(m);
 
1029
                        }
 
1030
                }
 
1031
                return new HandlerPrintStream();
 
1032
        }
 
1033
 
 
1034
        /** utility class */
 
1035
        private MessageUtil() {
 
1036
        }
 
1037
 
 
1038
        /**
 
1039
         * Handle all messages in the second handler using the first
 
1040
         * 
 
1041
         * @param handler the IMessageHandler sink for all messages in source
 
1042
         * @param holder the IMessageHolder source for all messages to handle
 
1043
         * @param fastFail if true, stop on first failure
 
1044
         * @return false if any sink.handleMessage(..) failed
 
1045
         */
 
1046
        public static boolean handleAll(IMessageHandler sink, IMessageHolder source, boolean fastFail) {
 
1047
                return handleAll(sink, source, null, true, fastFail);
 
1048
        }
 
1049
 
 
1050
        /**
 
1051
         * Handle messages in the second handler using the first
 
1052
         * 
 
1053
         * @param handler the IMessageHandler sink for all messages in source
 
1054
         * @param holder the IMessageHolder source for all messages to handle
 
1055
         * @param kind the IMessage.Kind to select, if not null
 
1056
         * @param orGreater if true, also accept greater kinds
 
1057
         * @param fastFail if true, stop on first failure
 
1058
         * @return false if any sink.handleMessage(..) failed
 
1059
         */
 
1060
        public static boolean handleAll(IMessageHandler sink, IMessageHolder source, IMessage.Kind kind, boolean orGreater,
 
1061
                        boolean fastFail) {
 
1062
                LangUtil.throwIaxIfNull(sink, "sink");
 
1063
                LangUtil.throwIaxIfNull(source, "source");
 
1064
                return handleAll(sink, source.getMessages(kind, orGreater), fastFail);
 
1065
        }
 
1066
 
 
1067
        /**
 
1068
         * Handle messages in the second handler using the first if they are NOT of this kind (optionally, or greater). If you pass null
 
1069
         * as the kind, then all messages are ignored and this returns true.
 
1070
         * 
 
1071
         * @param handler the IMessageHandler sink for all messages in source
 
1072
         * @param holder the IMessageHolder source for all messages to handle
 
1073
         * @param kind the IMessage.Kind to reject, if not null
 
1074
         * @param orGreater if true, also reject greater kinds
 
1075
         * @param fastFail if true, stop on first failure
 
1076
         * @return false if any sink.handleMessage(..) failed
 
1077
         */
 
1078
        public static boolean handleAllExcept(IMessageHandler sink, IMessageHolder source, IMessage.Kind kind, boolean orGreater,
 
1079
                        boolean fastFail) {
 
1080
                LangUtil.throwIaxIfNull(sink, "sink");
 
1081
                LangUtil.throwIaxIfNull(source, "source");
 
1082
                if (null == kind) {
 
1083
                        return true;
 
1084
                }
 
1085
                IMessage[] messages = getMessagesExcept(source, kind, orGreater);
 
1086
                return handleAll(sink, messages, fastFail);
 
1087
        }
 
1088
 
 
1089
        /**
 
1090
         * Handle messages in the sink.
 
1091
         * 
 
1092
         * @param handler the IMessageHandler sink for all messages in source
 
1093
         * @param sources the IMessage[] messages to handle
 
1094
         * @param fastFail if true, stop on first failure
 
1095
         * @return false if any sink.handleMessage(..) failed
 
1096
         * @throws IllegalArgumentException if sink is null
 
1097
         */
 
1098
        public static boolean handleAll(IMessageHandler sink, IMessage[] sources, boolean fastFail) {
 
1099
                LangUtil.throwIaxIfNull(sink, "sink");
 
1100
                if (LangUtil.isEmpty(sources)) {
 
1101
                        return true;
 
1102
                }
 
1103
                boolean result = true;
 
1104
                for (int i = 0; i < sources.length; i++) {
 
1105
                        if (!sink.handleMessage(sources[i])) {
 
1106
                                if (fastFail) {
 
1107
                                        return false;
 
1108
                                }
 
1109
                                if (result) {
 
1110
                                        result = false;
 
1111
                                }
 
1112
                        }
 
1113
                }
 
1114
                return result;
 
1115
        }
1122
1116
}