View Javadoc
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 }