1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.tools;
19
20 import java.io.PrintStream;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public final class Generate {
47
48 static final String PACKAGE_DECLARATION = "package %s;%n%n";
49
50 static enum Type {
51 CUSTOM {
52 @Override
53 String imports() {
54 return ""
55 + "import java.io.Serializable;%n"
56 + "import org.apache.logging.log4j.Level;%n"
57 + "import org.apache.logging.log4j.LogManager;%n"
58 + "import org.apache.logging.log4j.Logger;%n"
59 + "import org.apache.logging.log4j.Marker;%n"
60 + "import org.apache.logging.log4j.message.Message;%n"
61 + "import org.apache.logging.log4j.message.MessageFactory;%n"
62 + "import org.apache.logging.log4j.spi.AbstractLogger;%n"
63 + "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n"
64 + "import org.apache.logging.log4j.util.MessageSupplier;%n"
65 + "import org.apache.logging.log4j.util.Supplier;%n"
66 + "%n";
67 }
68
69 @Override
70 String declaration() {
71 return ""
72 + "/**%n"
73 + " * Custom Logger interface with convenience methods for%n"
74 + " * %s%n"
75 + " */%n"
76 + "public final class %s implements Serializable {%n"
77 + " private static final long serialVersionUID = " + System.nanoTime() + "L;%n"
78 + " private final ExtendedLoggerWrapper logger;%n"
79 + "%n";
80 }
81
82 @Override
83 String constructor() {
84 return ""
85 + "%n"
86 + " private %s(final Logger logger) {%n"
87 + " this.logger = new ExtendedLoggerWrapper((AbstractLogger) logger, logger.getName(), "
88 + "logger.getMessageFactory());%n"
89 + " }%n";
90 }
91
92 @Override
93 Class<?> generator() {
94 return CustomLogger.class;
95 }
96 },
97 EXTEND {
98 @Override
99 String imports() {
100 return ""
101 + "import org.apache.logging.log4j.Level;%n"
102 + "import org.apache.logging.log4j.LogManager;%n"
103 + "import org.apache.logging.log4j.Logger;%n"
104 + "import org.apache.logging.log4j.Marker;%n"
105 + "import org.apache.logging.log4j.message.Message;%n"
106 + "import org.apache.logging.log4j.message.MessageFactory;%n"
107 + "import org.apache.logging.log4j.spi.AbstractLogger;%n"
108 + "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n"
109 + "import org.apache.logging.log4j.util.MessageSupplier;%n"
110 + "import org.apache.logging.log4j.util.Supplier;%n"
111 + "%n";
112 }
113
114 @Override
115 String declaration() {
116 return ""
117 + "/**%n"
118 + " * Extended Logger interface with convenience methods for%n"
119 + " * %s%n"
120 + " */%n"
121 + "public final class %s extends ExtendedLoggerWrapper {%n"
122 + " private static final long serialVersionUID = " + System.nanoTime() + "L;%n"
123 + " private final ExtendedLoggerWrapper logger;%n"
124 + "%n";
125 }
126
127 @Override
128 String constructor() {
129 return ""
130 + "%n"
131 + " private %s(final Logger logger) {%n"
132 + " super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());%n"
133 + " this.logger = this;%n"
134 + " }%n";
135 }
136
137 @Override
138 Class<?> generator() {
139 return ExtendedLogger.class;
140 }
141 };
142 abstract String imports();
143
144 abstract String declaration();
145
146 abstract String constructor();
147
148 abstract Class<?> generator();
149 }
150
151 static final String FQCN_FIELD = ""
152 + " private static final String FQCN = %s.class.getName();%n";
153
154 static final String LEVEL_FIELD = ""
155 + " private static final Level %s = Level.forName(\"%s\", %d);%n";
156
157 static final String FACTORY_METHODS = ""
158 + "%n"
159 + " /**%n"
160 + " * Returns a custom Logger with the name of the calling class.%n"
161 + " * %n"
162 + " * @return The custom Logger for the calling class.%n"
163 + " */%n"
164 + " public static CLASSNAME create() {%n"
165 + " final Logger wrapped = LogManager.getLogger();%n"
166 + " return new CLASSNAME(wrapped);%n"
167 + " }%n"
168 + "%n"
169 + " /**%n"
170 + " * Returns a custom Logger using the fully qualified name of the Class as%n"
171 + " * the Logger name.%n"
172 + " * %n"
173 + " * @param loggerName The Class whose name should be used as the Logger name.%n"
174 + " * If null it will default to the calling class.%n"
175 + " * @return The custom Logger.%n"
176 + " */%n"
177 + " public static CLASSNAME create(final Class<?> loggerName) {%n"
178 + " final Logger wrapped = LogManager.getLogger(loggerName);%n"
179 + " return new CLASSNAME(wrapped);%n"
180 + " }%n"
181 + "%n"
182 + " /**%n"
183 + " * Returns a custom Logger using the fully qualified name of the Class as%n"
184 + " * the Logger name.%n"
185 + " * %n"
186 + " * @param loggerName The Class whose name should be used as the Logger name.%n"
187 + " * If null it will default to the calling class.%n"
188 + " * @param messageFactory The message factory is used only when creating a%n"
189 + " * logger, subsequent use does not change the logger but will log%n"
190 + " * a warning if mismatched.%n"
191 + " * @return The custom Logger.%n"
192 + " */%n"
193 + " public static CLASSNAME create(final Class<?> loggerName, final MessageFactory factory) {%n"
194 + " final Logger wrapped = LogManager.getLogger(loggerName, factory);%n"
195 + " return new CLASSNAME(wrapped);%n"
196 + " }%n"
197 + "%n"
198 + " /**%n"
199 + " * Returns a custom Logger using the fully qualified class name of the value%n"
200 + " * as the Logger name.%n"
201 + " * %n"
202 + " * @param value The value whose class name should be used as the Logger%n"
203 + " * name. If null the name of the calling class will be used as%n"
204 + " * the logger name.%n"
205 + " * @return The custom Logger.%n"
206 + " */%n"
207 + " public static CLASSNAME create(final Object value) {%n"
208 + " final Logger wrapped = LogManager.getLogger(value);%n"
209 + " return new CLASSNAME(wrapped);%n"
210 + " }%n"
211 + "%n"
212 + " /**%n"
213 + " * Returns a custom Logger using the fully qualified class name of the value%n"
214 + " * as the Logger name.%n"
215 + " * %n"
216 + " * @param value The value whose class name should be used as the Logger%n"
217 + " * name. If null the name of the calling class will be used as%n"
218 + " * the logger name.%n"
219 + " * @param messageFactory The message factory is used only when creating a%n"
220 + " * logger, subsequent use does not change the logger but will log%n"
221 + " * a warning if mismatched.%n"
222 + " * @return The custom Logger.%n"
223 + " */%n"
224 + " public static CLASSNAME create(final Object value, final MessageFactory factory) {%n"
225 + " final Logger wrapped = LogManager.getLogger(value, factory);%n"
226 + " return new CLASSNAME(wrapped);%n"
227 + " }%n"
228 + "%n"
229 + " /**%n"
230 + " * Returns a custom Logger with the specified name.%n"
231 + " * %n"
232 + " * @param name The logger name. If null the name of the calling class will%n"
233 + " * be used.%n"
234 + " * @return The custom Logger.%n"
235 + " */%n"
236 + " public static CLASSNAME create(final String name) {%n"
237 + " final Logger wrapped = LogManager.getLogger(name);%n"
238 + " return new CLASSNAME(wrapped);%n"
239 + " }%n"
240 + "%n"
241 + " /**%n"
242 + " * Returns a custom Logger with the specified name.%n"
243 + " * %n"
244 + " * @param name The logger name. If null the name of the calling class will%n"
245 + " * be used.%n"
246 + " * @param messageFactory The message factory is used only when creating a%n"
247 + " * logger, subsequent use does not change the logger but will log%n"
248 + " * a warning if mismatched.%n"
249 + " * @return The custom Logger.%n"
250 + " */%n"
251 + " public static CLASSNAME create(final String name, final MessageFactory factory) {%n"
252 + " final Logger wrapped = LogManager.getLogger(name, factory);%n"
253 + " return new CLASSNAME(wrapped);%n"
254 + " }%n";
255
256 static final String METHODS = ""
257 + "%n"
258 + " /**%n"
259 + " * Logs a message with the specific Marker at the {@code CUSTOM_LEVEL} level.%n"
260 + " * %n"
261 + " * @param marker the marker data specific to this log statement%n"
262 + " * @param msg the message string to be logged%n"
263 + " */%n"
264 + " public void methodName(final Marker marker, final Message msg) {%n"
265 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msg, (Throwable) null);%n"
266 + " }%n"
267 + "%n"
268 + " /**%n"
269 + " * Logs a message with the specific Marker at the {@code CUSTOM_LEVEL} level.%n"
270 + " * %n"
271 + " * @param marker the marker data specific to this log statement%n"
272 + " * @param msg the message string to be logged%n"
273 + " * @param t A Throwable or null.%n"
274 + " */%n"
275 + " public void methodName(final Marker marker, final Message msg, final Throwable t) {%n"
276 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msg, t);%n"
277 + " }%n"
278 + "%n"
279 + " /**%n"
280 + " * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
281 + " * %n"
282 + " * @param marker the marker data specific to this log statement%n"
283 + " * @param message the message object to log.%n"
284 + " */%n"
285 + " public void methodName(final Marker marker, final Object message) {%n"
286 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n"
287 + " }%n"
288 + "%n"
289 + " /**%n"
290 + " * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
291 + " * the {@link Throwable} {@code t} passed as parameter.%n"
292 + " * %n"
293 + " * @param marker the marker data specific to this log statement%n"
294 + " * @param message the message to log.%n"
295 + " * @param t the exception to log, including its stack trace.%n"
296 + " */%n"
297 + " public void methodName(final Marker marker, final Object message, final Throwable t) {%n"
298 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%n"
299 + " }%n"
300 + "%n"
301 + " /**%n"
302 + " * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
303 + " * %n"
304 + " * @param marker the marker data specific to this log statement%n"
305 + " * @param message the message object to log.%n"
306 + " */%n"
307 + " public void methodName(final Marker marker, final String message) {%n"
308 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n"
309 + " }%n"
310 + "%n"
311 + " /**%n"
312 + " * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
313 + " * %n"
314 + " * @param marker the marker data specific to this log statement%n"
315 + " * @param message the message to log; the format depends on the message factory.%n"
316 + " * @param params parameters to the message.%n"
317 + " * @see #getMessageFactory()%n"
318 + " */%n"
319 + " public void methodName(final Marker marker, final String message, final Object... params) {%n"
320 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, params);%n"
321 + " }%n"
322 + "%n"
323 + " /**%n"
324 + " * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
325 + " * the {@link Throwable} {@code t} passed as parameter.%n"
326 + " * %n"
327 + " * @param marker the marker data specific to this log statement%n"
328 + " * @param message the message to log.%n"
329 + " * @param t the exception to log, including its stack trace.%n"
330 + " */%n"
331 + " public void methodName(final Marker marker, final String message, final Throwable t) {%n"
332 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%n"
333 + " }%n"
334 + "%n"
335 + " /**%n"
336 + " * Logs the specified Message at the {@code CUSTOM_LEVEL} level.%n"
337 + " * %n"
338 + " * @param msg the message string to be logged%n"
339 + " */%n"
340 + " public void methodName(final Message msg) {%n"
341 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msg, (Throwable) null);%n"
342 + " }%n"
343 + "%n"
344 + " /**%n"
345 + " * Logs the specified Message at the {@code CUSTOM_LEVEL} level.%n"
346 + " * %n"
347 + " * @param msg the message string to be logged%n"
348 + " * @param t A Throwable or null.%n"
349 + " */%n"
350 + " public void methodName(final Message msg, final Throwable t) {%n"
351 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msg, t);%n"
352 + " }%n"
353 + "%n"
354 + " /**%n"
355 + " * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
356 + " * %n"
357 + " * @param message the message object to log.%n"
358 + " */%n"
359 + " public void methodName(final Object message) {%n"
360 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, (Throwable) null);%n"
361 + " }%n"
362 + "%n"
363 + " /**%n"
364 + " * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
365 + " * the {@link Throwable} {@code t} passed as parameter.%n"
366 + " * %n"
367 + " * @param message the message to log.%n"
368 + " * @param t the exception to log, including its stack trace.%n"
369 + " */%n"
370 + " public void methodName(final Object message, final Throwable t) {%n"
371 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n"
372 + " }%n"
373 + "%n"
374 + " /**%n"
375 + " * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
376 + " * %n"
377 + " * @param message the message object to log.%n"
378 + " */%n"
379 + " public void methodName(final String message) {%n"
380 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, (Throwable) null);%n"
381 + " }%n"
382 + "%n"
383 + " /**%n"
384 + " * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
385 + " * %n"
386 + " * @param message the message to log; the format depends on the message factory.%n"
387 + " * @param params parameters to the message.%n"
388 + " * @see #getMessageFactory()%n"
389 + " */%n"
390 + " public void methodName(final String message, final Object... params) {%n"
391 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, params);%n"
392 + " }%n"
393 + "%n"
394 + " /**%n"
395 + " * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
396 + " * the {@link Throwable} {@code t} passed as parameter.%n"
397 + " * %n"
398 + " * @param message the message to log.%n"
399 + " * @param t the exception to log, including its stack trace.%n"
400 + " */%n"
401 + " public void methodName(final String message, final Throwable t) {%n"
402 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n"
403 + " }%n"
404 + "%n"
405 + " /**%n"
406 + " * Logs a message which is only to be constructed if the logging level is the {@code CUSTOM_LEVEL}"
407 + "level.%n"
408 + " *%n"
409 + " * @param msgSupplier A function, which when called, produces the desired log message;%n"
410 + " * the format depends on the message factory.%n"
411 + " * @since 2.4%n"
412 + " */%n"
413 + " public void methodName(final Supplier<?> msgSupplier) {%n"
414 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, (Throwable) null);%n"
415 + " }%n"
416 + "%n"
417 + " /**%n"
418 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
419 + " * level) including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.%n"
420 + " *%n"
421 + " * @param msgSupplier A function, which when called, produces the desired log message;%n"
422 + " * the format depends on the message factory.%n"
423 + " * @param t the exception to log, including its stack trace.%n"
424 + " * @since 2.4%n"
425 + " */%n"
426 + " public void methodName(final Supplier<?> msgSupplier, final Throwable t) {%n"
427 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, t);%n"
428 + " }%n"
429 + "%n"
430 + " /**%n"
431 + " * Logs a message which is only to be constructed if the logging level is the%n"
432 + " * {@code CUSTOM_LEVEL} level with the specified Marker.%n"
433 + " *%n"
434 + " * @param marker the marker data specific to this log statement%n"
435 + " * @param msgSupplier A function, which when called, produces the desired log message;%n"
436 + " * the format depends on the message factory.%n"
437 + " * @since 2.4%n"
438 + " */%n"
439 + " public void methodName(final Marker marker, final Supplier<?> msgSupplier) {%n"
440 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, (Throwable) null);%n"
441 + " }%n"
442 + "%n"
443 + " /**%n"
444 + " * Logs a message with parameters which are only to be constructed if the logging level is the%n"
445 + " * {@code CUSTOM_LEVEL} level.%n"
446 + " *%n"
447 + " * @param marker the marker data specific to this log statement%n"
448 + " * @param message the message to log; the format depends on the message factory.%n"
449 + " * @param paramSuppliers An array of functions, which when called, produce the desired log"
450 + " message parameters.%n"
451 + " * @since 2.4%n"
452 + " */%n"
453 + " public void methodName(final Marker marker, final String message, final Supplier<?>..."
454 + " paramSuppliers) {%n"
455 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, paramSuppliers);%n"
456 + " }%n"
457 + "%n"
458 + " /**%n"
459 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
460 + " * level) with the specified Marker and including the stack trace of the {@link Throwable}%n"
461 + " * <code>t</code> passed as parameter.%n"
462 + " *%n"
463 + " * @param marker the marker data specific to this log statement%n"
464 + " * @param msgSupplier A function, which when called, produces the desired log message;%n"
465 + " * the format depends on the message factory.%n"
466 + " * @param t A Throwable or null.%n"
467 + " * @since 2.4%n"
468 + " */%n"
469 + " public void methodName(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {%n"
470 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, t);%n"
471 + " }%n"
472 + "%n"
473 + " /**%n"
474 + " * Logs a message with parameters which are only to be constructed if the logging level is%n"
475 + " * the {@code CUSTOM_LEVEL} level.%n"
476 + " *%n"
477 + " * @param message the message to log; the format depends on the message factory.%n"
478 + " * @param paramSuppliers An array of functions, which when called, produce the desired log"
479 + " message parameters.%n"
480 + " * @since 2.4%n"
481 + " */%n"
482 + " public void methodName(final String message, final Supplier<?>... paramSuppliers) {%n"
483 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, paramSuppliers);%n"
484 + " }%n"
485 + "%n"
486 + " /**%n"
487 + " * Logs a message which is only to be constructed if the logging level is the%n"
488 + " * {@code CUSTOM_LEVEL} level with the specified Marker. The {@code MessageSupplier} may or may%n"
489 + " * not use the {@link MessageFactory} to construct the {@code Message}.%n"
490 + " *%n"
491 + " * @param marker the marker data specific to this log statement%n"
492 + " * @param msgSupplier A function, which when called, produces the desired log message.%n"
493 + " * @since 2.4%n"
494 + " */%n"
495 + " public void methodName(final Marker marker, final MessageSupplier msgSupplier) {%n"
496 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, (Throwable) null);%n"
497 + " }%n"
498 + "%n"
499 + " /**%n"
500 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
501 + " * level) with the specified Marker and including the stack trace of the {@link Throwable}%n"
502 + " * <code>t</code> passed as parameter. The {@code MessageSupplier} may or may not use the%n"
503 + " * {@link MessageFactory} to construct the {@code Message}.%n"
504 + " *%n"
505 + " * @param marker the marker data specific to this log statement%n"
506 + " * @param msgSupplier A function, which when called, produces the desired log message.%n"
507 + " * @param t A Throwable or null.%n"
508 + " * @since 2.4%n"
509 + " */%n"
510 + " public void methodName(final Marker marker, final MessageSupplier msgSupplier, final "
511 + "Throwable t) {%n"
512 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, t);%n"
513 + " }%n"
514 + "%n"
515 + " /**%n"
516 + " * Logs a message which is only to be constructed if the logging level is the%n"
517 + " * {@code CUSTOM_LEVEL} level. The {@code MessageSupplier} may or may not use the%n"
518 + " * {@link MessageFactory} to construct the {@code Message}.%n"
519 + " *%n"
520 + " * @param msgSupplier A function, which when called, produces the desired log message.%n"
521 + " * @since 2.4%n"
522 + " */%n"
523 + " public void methodName(final MessageSupplier msgSupplier) {%n"
524 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, (Throwable) null);%n"
525 + " }%n"
526 + "%n"
527 + " /**%n"
528 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
529 + " * level) including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.%n"
530 + " * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the%n"
531 + " * {@code Message}.%n"
532 + " *%n"
533 + " * @param msgSupplier A function, which when called, produces the desired log message.%n"
534 + " * @param t the exception to log, including its stack trace.%n"
535 + " * @since 2.4%n"
536 + " */%n"
537 + " public void methodName(final MessageSupplier msgSupplier, final Throwable t) {%n"
538 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, t);%n"
539 + " }%n";
540
541 private Generate() {
542 }
543
544
545
546
547
548 public static final class CustomLogger {
549
550
551
552
553
554
555
556 public static void main(final String[] args) {
557 generate(args, Type.CUSTOM);
558 }
559
560 private CustomLogger() {
561 }
562 }
563
564
565
566
567
568
569 public static final class ExtendedLogger {
570
571
572
573
574
575
576
577 public static void main(final String[] args) {
578 generate(args, Type.EXTEND);
579 }
580
581 private ExtendedLogger() {
582 }
583 }
584
585 static class LevelInfo {
586 final String name;
587 final int intLevel;
588
589 LevelInfo(final String description) {
590 final String[] parts = description.split("=");
591 name = parts[0];
592 intLevel = Integer.parseInt(parts[1]);
593 }
594
595 public static List<LevelInfo> parse(final List<String> values, final Class<?> generator) {
596 final List<LevelInfo> result = new ArrayList<>(values.size());
597 for (int i = 0; i < values.size(); i++) {
598 try {
599 result.add(new LevelInfo(values.get(i)));
600 } catch (final Exception ex) {
601 System.err.println("Cannot parse custom level '" + values.get(i) + "': " + ex.toString());
602 usage(System.err, generator);
603 System.exit(-1);
604 }
605 }
606 return result;
607 }
608 }
609
610 private static void generate(final String[] args, final Type type) {
611 generate(args, type, System.out);
612 }
613
614 static void generate(final String[] args, final Type type, final PrintStream printStream) {
615 if (!validate(args)) {
616 usage(printStream, type.generator());
617 System.exit(-1);
618 }
619 final List<String> values = new ArrayList<>(Arrays.asList(args));
620 final String classFQN = values.remove(0);
621 final List<LevelInfo> levels = LevelInfo.parse(values, type.generator());
622 printStream.println(generateSource(classFQN, levels, type));
623 }
624
625 static boolean validate(final String[] args) {
626 if (args.length < 2) {
627 return false;
628 }
629 return true;
630 }
631
632 private static void usage(final PrintStream out, final Class<?> generator) {
633 out.println("Usage: java " + generator.getName() + " className LEVEL1=intLevel1 [LEVEL2=intLevel2...]");
634 out.println(" Where className is the fully qualified class name of the custom/extended logger");
635 out.println(" to generate, followed by a space-separated list of custom log levels.");
636 out.println(" For each custom log level, specify NAME=intLevel (without spaces).");
637 }
638
639 static String generateSource(final String classNameFQN, final List<LevelInfo> levels, final Type type) {
640 final StringBuilder sb = new StringBuilder(10000 * levels.size());
641 final int lastDot = classNameFQN.lastIndexOf('.');
642 final String pkg = classNameFQN.substring(0, lastDot >= 0 ? lastDot : 0);
643 if (!pkg.isEmpty()) {
644 sb.append(String.format(PACKAGE_DECLARATION, pkg));
645 }
646 sb.append(String.format(type.imports(), ""));
647 final String className = classNameFQN.substring(classNameFQN.lastIndexOf('.') + 1);
648 final String javadocDescr = javadocDescription(levels);
649 sb.append(String.format(type.declaration(), javadocDescr, className));
650 sb.append(String.format(FQCN_FIELD, className));
651 for (final LevelInfo level : levels) {
652 sb.append(String.format(LEVEL_FIELD, level.name, level.name, level.intLevel));
653 }
654 sb.append(String.format(type.constructor(), className));
655 sb.append(String.format(FACTORY_METHODS.replaceAll("CLASSNAME", className), ""));
656 for (final LevelInfo level : levels) {
657 final String methodName = camelCase(level.name);
658 final String phase1 = METHODS.replaceAll("CUSTOM_LEVEL", level.name);
659 final String phase2 = phase1.replaceAll("methodName", methodName);
660 sb.append(String.format(phase2, ""));
661 }
662
663 sb.append(String.format("}%n", ""));
664 return sb.toString();
665 }
666
667 static String javadocDescription(final List<LevelInfo> levels) {
668 if (levels.size() == 1) {
669 return "the " + levels.get(0).name + " custom log level.";
670 }
671 final StringBuilder sb = new StringBuilder(512);
672 sb.append("the ");
673 String sep = "";
674 for (int i = 0; i < levels.size(); i++) {
675 sb.append(sep);
676 sb.append(levels.get(i).name);
677 sep = (i == levels.size() - 2) ? " and " : ", ";
678 }
679 sb.append(" custom log levels.");
680 return sb.toString();
681 }
682
683 static String camelCase(final String customLevel) {
684 final StringBuilder sb = new StringBuilder(customLevel.length());
685 boolean lower = true;
686 for (final char ch : customLevel.toCharArray()) {
687 if (ch == '_') {
688 lower = false;
689 continue;
690 }
691 sb.append(lower ? Character.toLowerCase(ch) : Character.toUpperCase(ch));
692 lower = true;
693 }
694 return sb.toString();
695 }
696 }