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.datatype.markup.MarkupLine;
30 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
31 import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
32 import gov.nist.secauto.metaschema.core.metapath.MetapathExpression;
33 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
34 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
35 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
36 import gov.nist.secauto.metaschema.core.util.ReplacementScanner;
37
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.Set;
41 import java.util.regex.Pattern;
42
43 import javax.xml.namespace.QName;
44
45 import edu.umd.cs.findbugs.annotations.NonNull;
46 import edu.umd.cs.findbugs.annotations.Nullable;
47
48 public final class DefaultExpectConstraint
49 extends AbstractConstraint
50 implements IExpectConstraint {
51 @SuppressWarnings("null")
52 @NonNull
53 private static final Pattern METAPATH_VALUE_TEMPLATE_PATTERN
54 = Pattern.compile("(?<!\\\\)(\\{\\s*((?:(?:\\\\})|[^}])*)\\s*\\})");
55 @NonNull
56 private final MetapathExpression test;
57 private final String message;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 private DefaultExpectConstraint(
87 @Nullable String id,
88 @Nullable String formalName,
89 @Nullable MarkupLine description,
90 @NonNull ISource source,
91 @NonNull Level level,
92 @NonNull MetapathExpression target,
93 @NonNull Map<QName, Set<String>> properties,
94 @NonNull MetapathExpression test,
95 @Nullable String message,
96 MarkupMultiline remarks) {
97 super(id, formalName, description, source, level, target, properties, remarks);
98 this.test = Objects.requireNonNull(test);
99 this.message = message;
100 }
101
102 @Override
103 public MetapathExpression getTest() {
104 return test;
105 }
106
107 @Override
108 public String getMessage() {
109 return message;
110 }
111
112 @Override
113 public CharSequence generateMessage(@NonNull INodeItem item, @NonNull DynamicContext context) {
114 String message = getMessage();
115
116 return message == null ? null
117 : ReplacementScanner.replaceTokens(message, METAPATH_VALUE_TEMPLATE_PATTERN, match -> {
118 @SuppressWarnings("null")
119 @NonNull String metapath = match.group(2);
120 MetapathExpression expr = MetapathExpression.compile(metapath);
121 return expr.evaluateAs(item, MetapathExpression.ResultType.STRING, context);
122 });
123 }
124
125 @Override
126 public <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) {
127 return visitor.visitExpectConstraint(this, state);
128 }
129
130 @NonNull
131 public static Builder builder() {
132 return new Builder();
133 }
134
135 public static final class Builder
136 extends AbstractConstraintBuilder<Builder, DefaultExpectConstraint> {
137 private MetapathExpression test;
138 private String message;
139
140 private Builder() {
141
142 }
143
144 public Builder test(@NonNull MetapathExpression test) {
145 this.test = test;
146 return this;
147 }
148
149 public Builder message(@NonNull String message) {
150 this.message = message;
151 return this;
152 }
153
154 @Override
155 protected Builder getThis() {
156 return this;
157 }
158
159 @Override
160 protected void validate() {
161 super.validate();
162
163 ObjectUtils.requireNonNull(getTest());
164 }
165
166 protected MetapathExpression getTest() {
167 return test;
168 }
169
170 protected String getMessage() {
171 return message;
172 }
173
174 @Override
175 protected DefaultExpectConstraint newInstance() {
176 return new DefaultExpectConstraint(
177 getId(),
178 getFormalName(),
179 getDescription(),
180 ObjectUtils.notNull(getSource()),
181 getLevel(),
182 getTarget(),
183 getProperties(),
184 ObjectUtils.requireNonNull(getTest()),
185 getMessage(),
186 getRemarks());
187 }
188 }
189 }