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