1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.io;
7
8 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
9 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
10 import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
11 import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem;
12 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
13 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
14 import gov.nist.secauto.metaschema.core.model.IBoundObject;
15 import gov.nist.secauto.metaschema.core.model.constraint.ConstraintValidationException;
16 import gov.nist.secauto.metaschema.core.model.constraint.DefaultConstraintValidator;
17 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintValidationHandler;
18 import gov.nist.secauto.metaschema.core.model.constraint.LoggingConstraintValidationHandler;
19 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
20 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
21
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.net.URI;
25 import java.util.concurrent.locks.Lock;
26 import java.util.concurrent.locks.ReentrantLock;
27
28 import edu.umd.cs.findbugs.annotations.NonNull;
29
30
31
32
33
34
35
36 public abstract class AbstractDeserializer<CLASS extends IBoundObject>
37 extends AbstractSerializationBase<DeserializationFeature<?>>
38 implements IDeserializer<CLASS> {
39
40 private IConstraintValidationHandler constraintValidationHandler;
41 private final Lock handlerLock = new ReentrantLock();
42
43
44
45
46
47
48
49
50 protected AbstractDeserializer(@NonNull IBoundDefinitionModelAssembly definition) {
51 super(definition);
52 }
53
54
55
56
57
58
59
60 @Override
61 @NonNull
62 public IConstraintValidationHandler getConstraintValidationHandler() {
63 handlerLock.lock();
64 try {
65 if (constraintValidationHandler == null) {
66 constraintValidationHandler = new LoggingConstraintValidationHandler();
67 }
68 return ObjectUtils.notNull(constraintValidationHandler);
69 } finally {
70 handlerLock.unlock();
71 }
72 }
73
74 @Override
75 public void setConstraintValidationHandler(@NonNull IConstraintValidationHandler constraintValidationHandler) {
76 handlerLock.lock();
77 try {
78 this.constraintValidationHandler = constraintValidationHandler;
79 } finally {
80 handlerLock.unlock();
81 }
82 }
83
84 @Override
85 public INodeItem deserializeToNodeItem(Reader reader, URI documentUri) throws IOException {
86
87 INodeItem nodeItem;
88 try {
89 nodeItem = deserializeToNodeItemInternal(reader, documentUri);
90 } catch (Exception ex) {
91 throw new IOException(ex);
92 }
93
94 if (isValidating()) {
95 try {
96 validate(nodeItem);
97 } catch (ConstraintValidationException ex) {
98 throw new IOException(ex);
99 }
100 }
101 return nodeItem;
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115 @NonNull
116 protected abstract INodeItem deserializeToNodeItemInternal(@NonNull Reader reader, @NonNull URI documentUri)
117 throws IOException;
118
119 @Override
120 public final CLASS deserializeToValue(Reader reader, URI documentUri) throws IOException {
121 CLASS retval;
122
123 if (isValidating()) {
124 INodeItem nodeItem = deserializeToNodeItemInternal(reader, documentUri);
125 try {
126 validate(nodeItem);
127 } catch (ConstraintValidationException ex) {
128 throw new IOException(ex);
129 }
130 retval = ObjectUtils.asType(ObjectUtils.requireNonNull(nodeItem.getValue()));
131 } else {
132 retval = deserializeToValueInternal(reader, documentUri);
133 }
134 return retval;
135 }
136
137 private void validate(@NonNull INodeItem nodeItem) throws ConstraintValidationException {
138 IDefinitionNodeItem<?, ?> definitionNodeItem;
139 if (nodeItem instanceof IDocumentNodeItem) {
140 definitionNodeItem = ((IDocumentNodeItem) nodeItem).getRootAssemblyNodeItem();
141 } else if (nodeItem instanceof IDefinitionNodeItem) {
142 definitionNodeItem = (IDefinitionNodeItem<?, ?>) nodeItem;
143 } else {
144 throw new UnsupportedOperationException(String.format(
145 "The node item type '%s' is not supported for validation.",
146 nodeItem.getClass().getName()));
147 }
148
149 DynamicContext dynamicContext = new DynamicContext(nodeItem.getStaticContext());
150 dynamicContext.setDocumentLoader(getBindingContext().newBoundLoader());
151 DefaultConstraintValidator validator = new DefaultConstraintValidator(getConstraintValidationHandler());
152 validator.validate(definitionNodeItem, dynamicContext);
153 validator.finalizeValidation(dynamicContext);
154 }
155
156 @NonNull
157 protected abstract CLASS deserializeToValueInternal(@NonNull Reader reader, @NonNull URI documentUri)
158 throws IOException;
159
160 @Override
161 public IDeserializer<CLASS> enableFeature(DeserializationFeature<?> feature) {
162 return set(feature, true);
163 }
164
165 @Override
166 public IDeserializer<CLASS> disableFeature(DeserializationFeature<?> feature) {
167 return set(feature, false);
168 }
169
170 @Override
171 public IDeserializer<CLASS> applyConfiguration(
172 @NonNull IConfiguration<DeserializationFeature<?>> other) {
173 IMutableConfiguration<DeserializationFeature<?>> config = getConfiguration();
174 config.applyConfiguration(other);
175 configurationChanged(config);
176 return this;
177 }
178
179 @Override
180 public IDeserializer<CLASS> set(DeserializationFeature<?> feature, Object value) {
181 IMutableConfiguration<DeserializationFeature<?>> config = getConfiguration();
182 config.set(feature, value);
183 configurationChanged(config);
184 return this;
185 }
186 }