1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.cli.util;
28
29 import static org.fusesource.jansi.Ansi.ansi;
30
31 import gov.nist.secauto.metaschema.core.model.constraint.ConstraintValidationFinding;
32 import gov.nist.secauto.metaschema.core.model.constraint.IConstraint.Level;
33 import gov.nist.secauto.metaschema.core.model.validation.IValidationFinding;
34 import gov.nist.secauto.metaschema.core.model.validation.IValidationResult;
35 import gov.nist.secauto.metaschema.core.model.validation.JsonSchemaContentValidator.JsonValidationFinding;
36 import gov.nist.secauto.metaschema.core.model.validation.XmlSchemaContentValidator.XmlValidationFinding;
37
38 import org.apache.logging.log4j.LogBuilder;
39 import org.apache.logging.log4j.LogManager;
40 import org.apache.logging.log4j.Logger;
41 import org.fusesource.jansi.Ansi;
42 import org.fusesource.jansi.Ansi.Color;
43 import org.xml.sax.SAXParseException;
44
45 import java.util.List;
46
47 import edu.umd.cs.findbugs.annotations.NonNull;
48
49 public final class LoggingValidationHandler {
50 private static final Logger LOGGER = LogManager.getLogger(LoggingValidationHandler.class);
51
52 private static final LoggingValidationHandler NO_LOG_EXCPTION_INSTANCE = new LoggingValidationHandler(false);
53 private static final LoggingValidationHandler LOG_EXCPTION_INSTANCE = new LoggingValidationHandler(true);
54
55 private final boolean logExceptions;
56
57 public static LoggingValidationHandler instance() {
58 return instance(false);
59 }
60
61 public static LoggingValidationHandler instance(boolean logExceptions) {
62 return logExceptions ? LOG_EXCPTION_INSTANCE : NO_LOG_EXCPTION_INSTANCE;
63 }
64
65 protected LoggingValidationHandler(boolean logExceptions) {
66 this.logExceptions = logExceptions;
67 }
68
69 public boolean isLogExceptions() {
70 return logExceptions;
71 }
72
73 public boolean handleValidationResults(IValidationResult result) {
74 handleValidationFindings(result.getFindings());
75 return result.isPassing();
76 }
77
78 public void handleValidationFindings(@NonNull List<? extends IValidationFinding> findings) {
79 for (IValidationFinding finding : findings) {
80 if (finding instanceof JsonValidationFinding) {
81 handleJsonValidationFinding((JsonValidationFinding) finding);
82 } else if (finding instanceof XmlValidationFinding) {
83 handleXmlValidationFinding((XmlValidationFinding) finding);
84 } else if (finding instanceof ConstraintValidationFinding) {
85 handleConstraintValidationFinding((ConstraintValidationFinding) finding);
86 } else {
87 throw new IllegalStateException();
88 }
89 }
90 }
91
92 private void handleJsonValidationFinding(@NonNull JsonValidationFinding finding) {
93 Ansi ansi = generatePreamble(finding.getSeverity());
94
95 getLogger(finding).log(
96 ansi.a('[')
97 .fgBright(Color.WHITE)
98 .a(finding.getCause().getPointerToViolation())
99 .reset()
100 .a(']')
101 .format(" %s [%s]",
102 finding.getMessage(),
103 finding.getDocumentUri().toString()));
104 }
105
106 private void handleXmlValidationFinding(XmlValidationFinding finding) {
107 Ansi ansi = generatePreamble(finding.getSeverity());
108 SAXParseException ex = finding.getCause();
109
110 getLogger(finding).log(
111 ansi.format("%s [%s{%d,%d}]",
112 finding.getMessage(),
113 finding.getDocumentUri().toString(),
114 ex.getLineNumber(),
115 ex.getColumnNumber()));
116 }
117
118 private void handleConstraintValidationFinding(@NonNull ConstraintValidationFinding finding) {
119 Ansi ansi = generatePreamble(finding.getSeverity());
120
121 getLogger(finding).log(
122 ansi.format("[%s] %s", finding.getNode().getMetapath(), finding.getMessage()));
123 }
124
125 @NonNull
126 private LogBuilder getLogger(@NonNull IValidationFinding finding) {
127 LogBuilder retval;
128 switch (finding.getSeverity()) {
129 case CRITICAL:
130 retval = LOGGER.atFatal();
131 break;
132 case ERROR:
133 retval = LOGGER.atError();
134 break;
135 case WARNING:
136 retval = LOGGER.atWarn();
137 break;
138 case INFORMATIONAL:
139 retval = LOGGER.atInfo();
140 break;
141 default:
142 throw new IllegalArgumentException("Unknown level: " + finding.getSeverity().name());
143 }
144
145 assert retval != null;
146
147 if (finding.getCause() != null && isLogExceptions()) {
148 retval.withThrowable(finding.getCause());
149 }
150
151 return retval;
152 }
153
154 @SuppressWarnings("static-method")
155 @NonNull
156 private Ansi generatePreamble(@NonNull Level level) {
157 Ansi ansi = ansi().fgBright(Color.WHITE).a('[').reset();
158
159 switch (level) {
160 case CRITICAL:
161 ansi = ansi.fgRed().a("CRITICAL").reset();
162 break;
163 case ERROR:
164 ansi = ansi.fgBrightRed().a("ERROR").reset();
165 break;
166 case WARNING:
167 ansi = ansi.fgBrightYellow().a("WARNING").reset();
168 break;
169 case INFORMATIONAL:
170 ansi = ansi.fgBrightBlue().a("INFO").reset();
171 break;
172 default:
173 ansi = ansi().fgBright(Color.MAGENTA).a(level.name()).reset();
174 break;
175 }
176 ansi = ansi.fgBright(Color.WHITE).a("] ").reset();
177
178 assert ansi != null;
179 return ansi;
180 }
181 }