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.databind.io;
28
29 import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
30 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
31 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
32 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
33 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
34 import gov.nist.secauto.metaschema.core.resource.AbstractResourceLoader;
35 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
36 import gov.nist.secauto.metaschema.databind.IBindingContext;
37
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.net.URI;
41 import java.net.URL;
42 import java.util.Map;
43
44 import edu.umd.cs.findbugs.annotations.NonNull;
45
46
47
48
49 public class DefaultBoundLoader
50 extends AbstractResourceLoader
51 implements IBoundLoader {
52 public static final int LOOK_AHEAD_BYTES = 32_768;
53
54
55
56
57
58
59
60 private FormatDetector formatDetector;
61
62 private ModelDetector modelDetector;
63
64 @NonNull
65 private final IBindingContext bindingContext;
66 @NonNull
67 private final IMutableConfiguration<DeserializationFeature<?>> configuration;
68
69
70
71
72
73
74
75
76 public DefaultBoundLoader(@NonNull IBindingContext bindingContext) {
77 this.bindingContext = bindingContext;
78 this.configuration = new DefaultConfiguration<>();
79 }
80
81 @NonNull
82 private IMutableConfiguration<DeserializationFeature<?>> getConfiguration() {
83 return configuration;
84 }
85
86 @Override
87 public boolean isFeatureEnabled(DeserializationFeature<?> feature) {
88 return getConfiguration().isFeatureEnabled(feature);
89 }
90
91 @Override
92 public Map<DeserializationFeature<?>, Object> getFeatureValues() {
93 return getConfiguration().getFeatureValues();
94 }
95
96 @Override
97 public IBoundLoader applyConfiguration(@NonNull IConfiguration<DeserializationFeature<?>> other) {
98 getConfiguration().applyConfiguration(other);
99 resetDetector();
100 return this;
101 }
102
103 @SuppressWarnings("PMD.NullAssignment")
104 private void resetDetector() {
105
106 formatDetector = null;
107 }
108
109 @Override
110 public IBoundLoader set(DeserializationFeature<?> feature, Object value) {
111 getConfiguration().set(feature, value);
112 resetDetector();
113 return this;
114 }
115
116 @Override
117 public IBindingContext getBindingContext() {
118 return bindingContext;
119 }
120
121 @Override
122 public FormatDetector.Result detectFormat(@NonNull URI uri) throws IOException {
123 URI resourceUri = resolve(uri);
124 URL resource = resourceUri.toURL();
125
126 try (InputStream is = ObjectUtils.notNull(resource.openStream())) {
127 return detectFormat(is);
128 }
129 }
130
131 @Override
132 public FormatDetector.Result detectFormat(@NonNull InputStream is) throws IOException {
133 return getFormatDetector().detect(is);
134 }
135
136 @NonNull
137 private FormatDetector getFormatDetector() {
138 if (formatDetector == null) {
139 formatDetector = new FormatDetector(getConfiguration());
140 }
141 assert formatDetector != null;
142 return formatDetector;
143 }
144
145 @NonNull
146 private ModelDetector getModelDetector() {
147 if (modelDetector == null) {
148 modelDetector = new ModelDetector(
149 getBindingContext(),
150 getConfiguration());
151 }
152 assert modelDetector != null;
153 return modelDetector;
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 @Override
173 public <CLASS> CLASS load(@NonNull URI uri) throws IOException {
174 URI resourceUri = resolve(uri);
175 URL resource = resourceUri.toURL();
176
177 try (InputStream is = ObjectUtils.notNull(resource.openStream())) {
178 return load(is, uri);
179 }
180 }
181
182 @Override
183 @NonNull
184 public <CLASS> CLASS load(@NonNull InputStream is, @NonNull URI documentUri) throws IOException {
185
186 return INodeItem.toValue(loadAsNodeItem(is, documentUri));
187 }
188
189 @Override
190 public <CLASS> CLASS load(Class<CLASS> clazz, URI uri) throws IOException {
191 URI resourceUri = resolve(uri);
192 URL resource = resourceUri.toURL();
193
194 try (InputStream is = ObjectUtils.notNull(resource.openStream())) {
195 return load(clazz, is, resourceUri);
196 }
197 }
198
199 @Override
200 public <CLASS> CLASS load(Class<CLASS> clazz, InputStream is, URI documentUri) throws IOException {
201
202
203 FormatDetector.Result match = getFormatDetector().detect(is);
204 Format format = match.getFormat();
205
206 try (InputStream remainingStream = match.getDataStream()) {
207
208 return load(clazz, format, remainingStream, documentUri);
209 }
210 }
211
212 @NonNull
213 private <CLASS> CLASS load(
214 @NonNull Class<CLASS> clazz,
215 @NonNull Format format,
216 @NonNull InputStream is,
217 @NonNull URI documentUri) throws IOException {
218
219 IDeserializer<CLASS> deserializer = getDeserializer(clazz, format, getConfiguration());
220 return deserializer.deserialize(is, documentUri);
221 }
222
223 @Override
224 public IDocumentNodeItem loadAsNodeItem(URI uri) throws IOException {
225 URI resourceUri = resolve(uri);
226 URL resource = resourceUri.toURL();
227
228 try (InputStream is = ObjectUtils.notNull(resource.openStream())) {
229 return loadAsNodeItem(is, resourceUri);
230 }
231 }
232
233 @Override
234 public IDocumentNodeItem loadAsNodeItem(InputStream is, URI documentUri) throws IOException {
235 FormatDetector.Result formatMatch = getFormatDetector().detect(is);
236 Format format = formatMatch.getFormat();
237
238 try (InputStream formatStream = formatMatch.getDataStream()) {
239 return loadAsNodeItem(format, formatStream, documentUri);
240 }
241 }
242
243 @Override
244 public IDocumentNodeItem loadAsNodeItem(Format format, URI uri) throws IOException {
245 URI resourceUri = resolve(uri);
246 URL resource = resourceUri.toURL();
247
248 try (InputStream is = ObjectUtils.notNull(resource.openStream())) {
249 return loadAsNodeItem(format, is, resourceUri);
250 }
251 }
252
253 @Override
254 public IDocumentNodeItem loadAsNodeItem(Format format, InputStream is, URI documentUri) throws IOException {
255 ModelDetector.Result modelMatch = getModelDetector().detect(is, format);
256
257 IDeserializer<?> deserializer = getDeserializer(
258 modelMatch.getBoundClass(),
259 format,
260 getConfiguration());
261 try (InputStream modelStream = modelMatch.getDataStream()) {
262 return (IDocumentNodeItem) deserializer.deserializeToNodeItem(modelStream, documentUri);
263 }
264 }
265
266 @NonNull
267 private <CLASS> IDeserializer<CLASS> getDeserializer(
268 @NonNull Class<CLASS> clazz,
269 @NonNull Format format,
270 @NonNull IConfiguration<DeserializationFeature<?>> config) {
271 IDeserializer<CLASS> retval = getBindingContext().newDeserializer(format, clazz);
272 retval.applyConfiguration(config);
273 return retval;
274 }
275 }