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.core.model.constraint;
28
29 import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
30 import gov.nist.secauto.metaschema.core.metapath.ISequence;
31 import gov.nist.secauto.metaschema.core.metapath.MetapathException;
32 import gov.nist.secauto.metaschema.core.metapath.format.IPathFormatter;
33 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
34 import gov.nist.secauto.metaschema.core.model.constraint.IConstraint.Level;
35 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
36
37 import org.apache.logging.log4j.LogBuilder;
38 import org.apache.logging.log4j.LogManager;
39 import org.apache.logging.log4j.Logger;
40
41 import java.util.Comparator;
42 import java.util.List;
43 import java.util.Objects;
44
45 import edu.umd.cs.findbugs.annotations.NonNull;
46 import edu.umd.cs.findbugs.annotations.Nullable;
47
48 public class LoggingConstraintValidationHandler
49 extends AbstractConstraintValidationHandler {
50 private static final Logger LOGGER = LogManager.getLogger(DefaultConstraintValidator.class);
51 @NonNull
52 private IPathFormatter pathFormatter = IPathFormatter.METAPATH_PATH_FORMATER;
53
54 @Override
55 @NonNull
56 public IPathFormatter getPathFormatter() {
57 return pathFormatter;
58 }
59
60 public void setPathFormatter(@NonNull IPathFormatter pathFormatter) {
61 this.pathFormatter = Objects.requireNonNull(pathFormatter, "pathFormatter");
62 }
63
64 protected LogBuilder getLogBuilder(@NonNull Level level) {
65 LogBuilder retval;
66 switch (level) {
67 case CRITICAL:
68 retval = LOGGER.atFatal();
69 break;
70 case ERROR:
71 retval = LOGGER.atError();
72 break;
73 case WARNING:
74 retval = LOGGER.atWarn();
75 break;
76 case INFORMATIONAL:
77 retval = LOGGER.atInfo();
78 break;
79 default:
80 throw new UnsupportedOperationException(String.format("unsupported level '%s'", level));
81 }
82 return retval;
83 }
84
85 @Override
86 protected String toPath(@NonNull INodeItem nodeItem) {
87 return nodeItem.toPath(getPathFormatter());
88 }
89
90 protected boolean isLogged(@NonNull Level level) {
91 boolean retval;
92 switch (level) {
93 case CRITICAL:
94 retval = LOGGER.isFatalEnabled();
95 break;
96 case ERROR:
97 retval = LOGGER.isErrorEnabled();
98 break;
99 case WARNING:
100 retval = LOGGER.isWarnEnabled();
101 break;
102 case INFORMATIONAL:
103 retval = LOGGER.isInfoEnabled();
104 break;
105 default:
106 throw new UnsupportedOperationException(String.format("unsupported level '%s'", level));
107 }
108 return retval;
109 }
110
111 protected void logConstraint(
112 @NonNull Level level,
113 @NonNull INodeItem node,
114 @NonNull CharSequence message,
115 @Nullable Throwable cause) {
116 LogBuilder builder = getLogBuilder(level);
117 if (cause != null) {
118 builder.withThrowable(cause);
119 }
120
121 builder.log("{}: ({}) {}", level.name(), toPath(node), message);
122 }
123
124 @Override
125 public void handleCardinalityMinimumViolation(
126 @NonNull ICardinalityConstraint constraint,
127 @NonNull INodeItem node,
128 @NonNull ISequence<? extends INodeItem> targets) {
129 Level level = constraint.getLevel();
130 if (isLogged(level)) {
131 logConstraint(level, node, newCardinalityMinimumViolationMessage(constraint, node, targets), null);
132 }
133 }
134
135 @Override
136 public void handleCardinalityMaximumViolation(
137 @NonNull ICardinalityConstraint constraint,
138 @NonNull INodeItem node,
139 @NonNull ISequence<? extends INodeItem> targets) {
140 Level level = constraint.getLevel();
141 if (isLogged(level)) {
142 logConstraint(level, node, newCardinalityMaximumViolationMessage(constraint, node, targets), null);
143 }
144 }
145
146 @Override
147 public void handleIndexDuplicateKeyViolation(
148 @NonNull IIndexConstraint constraint,
149 @NonNull INodeItem node,
150 @NonNull INodeItem oldItem,
151 @NonNull INodeItem target) {
152 Level level = constraint.getLevel();
153 if (isLogged(level)) {
154 logConstraint(level, target, newIndexDuplicateKeyViolationMessage(constraint, node, oldItem, target), null);
155 }
156 }
157
158 @Override
159 public void handleUniqueKeyViolation(
160 @NonNull IUniqueConstraint constraint,
161 @NonNull INodeItem node,
162 @NonNull INodeItem oldItem,
163 @NonNull INodeItem target) {
164 Level level = constraint.getLevel();
165 if (isLogged(level)) {
166 logConstraint(level, target, newUniqueKeyViolationMessage(constraint, node, oldItem, target), null);
167 }
168 }
169
170 @SuppressWarnings("null")
171 @Override
172 public void handleKeyMatchError(
173 @NonNull IKeyConstraint constraint,
174 @NonNull INodeItem node,
175 @NonNull INodeItem target,
176 @NonNull MetapathException cause) {
177 Level level = constraint.getLevel();
178 if (isLogged(level)) {
179 logConstraint(level, target, cause.getLocalizedMessage(), cause);
180 }
181 }
182
183 @Override
184 public void handleMatchPatternViolation(
185 @NonNull IMatchesConstraint constraint,
186 @NonNull INodeItem node,
187 @NonNull INodeItem target,
188 @NonNull String value) {
189 Level level = constraint.getLevel();
190 if (isLogged(level)) {
191 logConstraint(level, target, newMatchPatternViolationMessage(constraint, node, target, value), null);
192 }
193 }
194
195 @Override
196 public void handleMatchDatatypeViolation(
197 @NonNull IMatchesConstraint constraint,
198 @NonNull INodeItem node,
199 @NonNull INodeItem target,
200 @NonNull String value,
201 @NonNull IllegalArgumentException cause) {
202 Level level = constraint.getLevel();
203 if (isLogged(level)) {
204 logConstraint(level, target, newMatchDatatypeViolationMessage(constraint, node, target, value), cause);
205 }
206 }
207
208 @Override
209 public void handleExpectViolation(
210 @NonNull IExpectConstraint constraint,
211 @NonNull INodeItem node,
212 @NonNull INodeItem target,
213 @NonNull DynamicContext dynamicContext) {
214 Level level = constraint.getLevel();
215 if (isLogged(level)) {
216 logConstraint(level, target, newExpectViolationMessage(constraint, node, target, dynamicContext), null);
217 }
218 }
219
220 @Override
221 public void handleAllowedValuesViolation(@NonNull List<IAllowedValuesConstraint> failedConstraints,
222 @NonNull INodeItem target) {
223
224 Level level = ObjectUtils.notNull(failedConstraints.stream()
225 .map(IConstraint::getLevel)
226 .max(Comparator.comparing(Level::ordinal))
227 .get());
228 if (isLogged(level)) {
229 logConstraint(level, target, newAllowedValuesViolationMessage(failedConstraints, target), null);
230 }
231 }
232
233 @Override
234 public void handleIndexDuplicateViolation(IIndexConstraint constraint, INodeItem node) {
235 Level level = Level.CRITICAL;
236 if (isLogged(level)) {
237 logConstraint(level, node, newIndexDuplicateViolationMessage(constraint, node), null);
238 }
239 }
240
241 @Override
242 public void handleIndexMiss(IIndexHasKeyConstraint constraint, INodeItem node, INodeItem target, List<String> key) {
243 Level level = constraint.getLevel();
244 if (isLogged(level)) {
245 logConstraint(level, node, newIndexMissMessage(constraint, node, target, key), null);
246 }
247 }
248
249 }