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