1 /*
2 * Portions of this software was developed by employees of the National Institute
3 * of Standards and Technology (NIST), an agency of the Federal Government and is
4 * being made available as a public service. Pursuant to title 17 United States
5 * Code Section 105, works of NIST employees are not subject to copyright
6 * protection in the United States. This software may be subject to foreign
7 * copyright. Permission in the United States and in foreign countries, to the
8 * extent that NIST may hold copyright, to use, copy, modify, create derivative
9 * works, and distribute this software and its documentation without fee is hereby
10 * granted on a non-exclusive basis, provided that this notice and disclaimer
11 * of warranty appears in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT
19 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
25 */
26
27 package gov.nist.secauto.metaschema.databind.io;
28
29 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
30 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
31 import gov.nist.secauto.metaschema.core.metapath.IDocumentLoader;
32 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
33 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
34 import gov.nist.secauto.metaschema.databind.DefaultBindingContext;
35 import gov.nist.secauto.metaschema.databind.IBindingContext;
36
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.io.OutputStream;
42 import java.net.URI;
43 import java.net.URISyntaxException;
44 import java.net.URL;
45 import java.nio.file.Path;
46
47 import edu.umd.cs.findbugs.annotations.NonNull;
48
49 /**
50 * A common interface for loading Module based instance resources.
51 */
52 public interface IBoundLoader extends IDocumentLoader, IMutableConfiguration<DeserializationFeature<?>> {
53
54 @Override
55 default IBoundLoader enableFeature(DeserializationFeature<?> feature) {
56 return set(feature, true);
57 }
58
59 @Override
60 default IBoundLoader disableFeature(DeserializationFeature<?> feature) {
61 return set(feature, false);
62 }
63
64 @Override
65 IBoundLoader applyConfiguration(IConfiguration<DeserializationFeature<?>> other);
66
67 @Override
68 IBoundLoader set(DeserializationFeature<?> feature, Object value);
69
70 /**
71 * Determine the format of the provided resource.
72 *
73 * @param file
74 * the resource
75 * @return the format information for the provided resource
76 * @throws IOException
77 * if an error occurred while reading the resource
78 */
79 @NonNull
80 default FormatDetector.Result detectFormat(@NonNull File file) throws IOException {
81 return detectFormat(ObjectUtils.notNull(file.toPath()));
82 }
83
84 /**
85 * Determine the format of the provided resource.
86 *
87 * @param path
88 * the resource
89 * @return the format information for the provided resource
90 * @throws IOException
91 * if an error occurred while reading the resource
92 */
93 @NonNull
94 default FormatDetector.Result detectFormat(@NonNull Path path) throws IOException {
95 return detectFormat(ObjectUtils.notNull(path.toUri()));
96 }
97
98 /**
99 * Determine the format of the provided resource.
100 *
101 * @param url
102 * the resource
103 * @return the format information for the provided resource
104 * @throws IOException
105 * if an error occurred while reading the resource
106 */
107 @NonNull
108 default FormatDetector.Result detectFormat(@NonNull URL url) throws IOException {
109 try {
110 return detectFormat(ObjectUtils.notNull(url.toURI()));
111 } catch (URISyntaxException ex) {
112 throw new IOException(ex);
113 }
114 }
115
116 /**
117 * Determine the format of the resource identified by the provided {@code uri}.
118 *
119 * @param uri
120 * the resource
121 * @return the format information for the provided resource
122 * @throws IOException
123 * if an error occurred while reading the resource
124 */
125 @NonNull
126 FormatDetector.Result detectFormat(@NonNull URI uri) throws IOException;
127
128 /**
129 * Determine the format of the provided resource.
130 * <p>
131 * This method will consume data from the provided {@link InputStream}. If the
132 * caller of this method intends to read data from the stream after determining
133 * the format, the caller should pass in a stream that can be reset.
134 * <p>
135 * This method will not close the provided {@link InputStream}, since it does
136 * not own the stream.
137 *
138 * @param is
139 * an input stream for the resource
140 * @return the format information for the provided resource
141 * @throws IOException
142 * if an error occurred while reading the resource
143 */
144 @NonNull
145 FormatDetector.Result detectFormat(@NonNull InputStream is) throws IOException;
146
147 //
148 // /**
149 // * Determine the format of the provided resource.
150 // * <p>
151 // * This method will consume data from any {@link InputStream} provided by the
152 // * {@link InputSource}. If the caller of this method intends to read data from
153 // * the stream after determining the format, the caller should pass in a stream
154 // * that can be reset.
155 // * <p>
156 // * This method will not close any {@link InputStream} provided by the
157 // * {@link InputSource}, since it does not own the stream.
158 // *
159 // * @param source
160 // * information about how to access the resource
161 // * @return the format of the provided resource
162 // * @throws IOException
163 // * if an error occurred while reading the resource
164 // */
165 // @NonNull
166 // Format detectFormat(@NonNull InputSource source) throws IOException;
167
168 /**
169 * Load data from the provided resource into a bound object.
170 * <p>
171 * This method will auto-detect the format of the provided resource.
172 *
173 * @param <CLASS>
174 * the type of the bound object to return
175 * @param file
176 * the resource
177 * @return a bound object containing the loaded data
178 * @throws IOException
179 * if an error occurred while reading the resource
180 * @see #detectFormat(File)
181 */
182 @NonNull
183 default <CLASS> CLASS load(@NonNull File file) throws IOException {
184 return load(ObjectUtils.notNull(file.toPath()));
185 }
186
187 /**
188 * Load data from the provided resource into a bound object.
189 * <p>
190 * This method will auto-detect the format of the provided resource.
191 *
192 * @param <CLASS>
193 * the type of the bound object to return
194 * @param path
195 * the resource
196 * @return a bound object containing the loaded data
197 * @throws IOException
198 * if an error occurred while reading the resource
199 * @see #detectFormat(File)
200 */
201 @NonNull
202 default <CLASS> CLASS load(@NonNull Path path) throws IOException {
203 return load(ObjectUtils.notNull(path.toUri()));
204 }
205
206 /**
207 * Load data from the provided resource into a bound object.
208 * <p>
209 * This method will auto-detect the format of the provided resource.
210 *
211 * @param <CLASS>
212 * the type of the bound object to return
213 * @param url
214 * the resource
215 * @return a bound object containing the loaded data
216 * @throws IOException
217 * if an error occurred while reading the resource
218 * @throws URISyntaxException
219 * if the provided {@code url} is malformed
220 * @see #detectFormat(URL)
221 */
222 @NonNull
223 default <CLASS> CLASS load(@NonNull URL url) throws IOException, URISyntaxException {
224 return load(ObjectUtils.notNull(url.toURI()));
225 }
226
227 /**
228 * Load data from the resource identified by the provided {@code uri} into a
229 * bound object.
230 * <p>
231 * This method will auto-detect the format of the provided resource.
232 *
233 * @param <CLASS>
234 * the type of the bound object to return
235 * @param uri
236 * the resource
237 * @return a bound object containing the loaded data
238 * @throws IOException
239 * if an error occurred while reading the resource
240 * @see #detectFormat(URL)
241 */
242 @NonNull
243 <CLASS> CLASS load(@NonNull URI uri) throws IOException;
244
245 /**
246 * Load data from the provided resource into a bound object.
247 * <p>
248 * This method should auto-detect the format of the provided resource.
249 * <p>
250 * This method will not close the provided {@link InputStream}, since it does
251 * not own the stream.
252 *
253 * @param <CLASS>
254 * the type of the bound object to return
255 * @param is
256 * the resource stream
257 * @param documentUri
258 * the URI of the resource
259 * @return a bound object containing the loaded data
260 * @throws IOException
261 * if an error occurred while reading the resource
262 * @see #detectFormat(InputStream)
263 */
264 @NonNull
265 <CLASS> CLASS load(@NonNull InputStream is, @NonNull URI documentUri) throws IOException;
266
267 /**
268 * Load data from the specified resource into a bound object with the type of
269 * the specified Java class.
270 *
271 * @param <CLASS>
272 * the Java type to load data into
273 * @param clazz
274 * the class for the java type
275 * @param file
276 * the resource to load
277 * @return the loaded instance data
278 * @throws IOException
279 * if an error occurred while loading the data in the specified file
280 */
281 @NonNull
282 default <CLASS> CLASS load(
283 @NonNull Class<CLASS> clazz,
284 @NonNull File file) throws IOException {
285 return load(clazz, ObjectUtils.notNull(file.toPath()));
286 }
287
288 /**
289 * Load data from the specified resource into a bound object with the type of
290 * the specified Java class.
291 *
292 * @param <CLASS>
293 * the Java type to load data into
294 * @param clazz
295 * the class for the java type
296 * @param path
297 * the resource to load
298 * @return the loaded instance data
299 * @throws IOException
300 * if an error occurred while loading the data in the specified file
301 */
302 @NonNull
303 default <CLASS> CLASS load(
304 @NonNull Class<CLASS> clazz,
305 @NonNull Path path) throws IOException {
306 return load(clazz, ObjectUtils.notNull(path.toUri()));
307 }
308
309 /**
310 * Load data from the specified resource into a bound object with the type of
311 * the specified Java class.
312 *
313 * @param <CLASS>
314 * the Java type to load data into
315 * @param clazz
316 * the class for the java type
317 * @param url
318 * the resource to load
319 * @return the loaded instance data
320 * @throws IOException
321 * if an error occurred while loading the data in the specified file
322 * @throws URISyntaxException
323 * if the provided {@code url} is malformed
324 */
325 @NonNull
326 default <CLASS> CLASS load(
327 @NonNull Class<CLASS> clazz,
328 @NonNull URL url) throws IOException, URISyntaxException {
329 return load(clazz, ObjectUtils.notNull(url.toURI()));
330 }
331
332 /**
333 * Load data from the specified resource into a bound object with the type of
334 * the specified Java class.
335 *
336 * @param <CLASS>
337 * the Java type to load data into
338 * @param clazz
339 * the class for the java type
340 * @param uri
341 * the resource to load
342 * @return the loaded instance data
343 * @throws IOException
344 * if an error occurred while loading the data in the specified file
345 */
346 @NonNull
347 <CLASS> CLASS load(
348 @NonNull Class<CLASS> clazz,
349 @NonNull URI uri) throws IOException;
350
351 /**
352 * Load data from the specified resource into a bound object with the type of
353 * the specified Java class.
354 * <p>
355 * This method will not close the provided {@link InputStream}, since it does
356 * not own the stream.
357 * <p>
358 * Implementations of this method will do format detection. This process might
359 * leave the provided {@link InputStream} at a position beyond the last parsed
360 * location. If you want to avoid this possibility, use and implementation of
361 * {@link IDeserializer#deserialize(InputStream, URI)} instead, such as what is
362 * provided by {@link DefaultBindingContext#newDeserializer(Format, Class)}.
363 *
364 * @param <CLASS>
365 * the Java type to load data into
366 * @param clazz
367 * the class for the java type
368 * @param is
369 * the resource stream
370 * @param documentUri
371 * the URI of the resource
372 * @return the loaded data
373 * @throws IOException
374 * if an error occurred while loading the data from the specified
375 * resource
376 */
377 @NonNull
378 <CLASS> CLASS load(
379 @NonNull Class<CLASS> clazz,
380 @NonNull InputStream is,
381 @NonNull URI documentUri) throws IOException;
382
383 /**
384 * Load data expressed using the provided {@code format} and return that data as
385 * a Metapath node item.
386 * <p>
387 * The specific Module model is auto-detected by analyzing the source. The class
388 * reported is implementation specific.
389 *
390 * @param format
391 * the expected format of the data to parse
392 * @param path
393 * the resource
394 * @return the Metapath node item for the parsed data
395 * @throws IOException
396 * if an error occurred while loading the data from the specified
397 * resource
398 */
399 @NonNull
400 default IDocumentNodeItem loadAsNodeItem(
401 @NonNull Format format,
402 @NonNull Path path) throws IOException {
403 return loadAsNodeItem(format, ObjectUtils.notNull(path.toUri()));
404 }
405
406 /**
407 * Load data expressed using the provided {@code format} and return that data as
408 * a Metapath node item.
409 * <p>
410 * The specific Module model is auto-detected by analyzing the source. The class
411 * reported is implementation specific.
412 *
413 * @param format
414 * the expected format of the data to parse
415 * @param uri
416 * the resource
417 * @return the Metapath node item for the parsed data
418 * @throws IOException
419 * if an error occurred while loading the data from the specified
420 * resource
421 */
422 @NonNull
423 IDocumentNodeItem loadAsNodeItem(
424 @NonNull Format format,
425 @NonNull URI uri) throws IOException;
426
427 /**
428 * Load data expressed using the provided {@code format} and return that data as
429 * a Metapath node item.
430 * <p>
431 * The specific Module model is auto-detected by analyzing the source. The class
432 * reported is implementation specific.
433 *
434 * @param format
435 * the expected format of the data to parse
436 * @param is
437 * the resource stream
438 * @param documentUri
439 * the URI of the resource
440 * @return the Metapath node item for the parsed data
441 * @throws IOException
442 * if an error occurred while loading the data from the specified
443 * resource
444 */
445 @NonNull
446 IDocumentNodeItem loadAsNodeItem(
447 @NonNull Format format,
448 @NonNull InputStream is,
449 @NonNull URI documentUri) throws IOException;
450
451 /**
452 * Get the configured Module binding context to use to load Java types.
453 *
454 * @return the binding context
455 */
456 @NonNull
457 IBindingContext getBindingContext();
458
459 /**
460 * Auto convert the provided {@code source} to the provided {@code toFormat}.
461 * Write the converted content to the provided {@code destination}.
462 * <p>
463 * The format of the source is expected to be auto detected using
464 * {@link #detectFormat(Path)}.
465 *
466 * @param <CLASS>
467 * the Java type to load data into
468 * @param source
469 * the resource to convert
470 * @param destination
471 * the resource to write converted content to
472 * @param toFormat
473 * the format to convert to
474 * @param rootClass
475 * the class for the Java type to load data into
476 * @throws FileNotFoundException
477 * the the provided source file was not found
478 * @throws IOException
479 * if an error occurred while loading the data from the specified
480 * resource or writing the converted data to the specified destination
481 */
482 default <CLASS> void convert(
483 @NonNull Path source,
484 @NonNull Path destination,
485 @NonNull Format toFormat,
486 @NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
487 CLASS object = load(rootClass, source);
488
489 ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
490 serializer.serialize(object, destination);
491 }
492
493 /**
494 * Auto convert the provided {@code source} to the provided {@code toFormat}.
495 * Write the converted content to the provided {@code destination}.
496 * <p>
497 * The format of the source is expected to be auto detected using
498 * {@link #detectFormat(Path)}.
499 *
500 * @param <CLASS>
501 * the Java type to load data into
502 * @param source
503 * the resource to convert
504 * @param os
505 * the output stream to write converted content to
506 * @param toFormat
507 * the format to convert to
508 * @param rootClass
509 * the class for the Java type to load data into
510 * @throws FileNotFoundException
511 * the the provided source file was not found
512 * @throws IOException
513 * if an error occurred while loading the data from the specified
514 * resource or writing the converted data to the specified destination
515 */
516 default <CLASS> void convert(
517 @NonNull Path source,
518 @NonNull OutputStream os,
519 @NonNull Format toFormat,
520 @NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
521 CLASS object = load(rootClass, source);
522
523 ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
524 serializer.serialize(object, os);
525 }
526 }