IBoundLoader.java
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/
package gov.nist.secauto.metaschema.databind.io;
import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
import gov.nist.secauto.metaschema.core.metapath.IDocumentLoader;
import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
import gov.nist.secauto.metaschema.core.model.IBoundObject;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import gov.nist.secauto.metaschema.databind.DefaultBindingContext;
import gov.nist.secauto.metaschema.databind.IBindingContext;
import org.eclipse.jdt.annotation.Owning;
import org.xml.sax.InputSource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import edu.umd.cs.findbugs.annotations.NonNull;
/**
* A common interface for loading Module based instance resources.
*/
public interface IBoundLoader extends IDocumentLoader, IMutableConfiguration<DeserializationFeature<?>> {
@Override
default IBoundLoader enableFeature(DeserializationFeature<?> feature) {
return set(feature, true);
}
@Override
default IBoundLoader disableFeature(DeserializationFeature<?> feature) {
return set(feature, false);
}
@Override
IBoundLoader applyConfiguration(IConfiguration<DeserializationFeature<?>> other);
@Override
IBoundLoader set(DeserializationFeature<?> feature, Object value);
/**
* Determine the format of the provided resource.
*
* @param file
* the resource
* @return the format information for the provided resource
* @throws IOException
* if an error occurred while reading the resource
*/
@NonNull
default Format detectFormat(@NonNull File file) throws IOException {
return detectFormat(ObjectUtils.notNull(file.toPath()));
}
/**
* Determine the format of the provided resource.
*
* @param path
* the resource
* @return the format information for the provided resource
* @throws IOException
* if an error occurred while reading the resource
*/
@NonNull
default Format detectFormat(@NonNull Path path) throws IOException {
return detectFormat(ObjectUtils.notNull(path.toUri()));
}
/**
* Determine the format of the provided resource.
*
* @param url
* the resource
* @return the format information for the provided resource
* @throws IOException
* if an error occurred while reading the resource
*/
@NonNull
default Format detectFormat(@NonNull URL url) throws IOException {
try {
return detectFormat(ObjectUtils.notNull(url.toURI()));
} catch (URISyntaxException ex) {
throw new IOException(ex);
}
}
/**
* Determine the format of the resource identified by the provided {@code uri}.
*
* @param uri
* the resource
* @return the format information for the provided resource
* @throws IOException
* if an error occurred while reading the resource
*/
@NonNull
Format detectFormat(@NonNull URI uri) throws IOException;
/**
* Determine the format of the provided resource.
* <p>
* This method will consume data from the provided {@link InputStream}. If the
* caller of this method intends to read data from the stream after determining
* the format, the caller should pass in a stream that can be reset.
* <p>
* This method will not close the provided {@link InputStream}, since it does
* not own the stream.
*
* @param is
* an input stream for the resource
* @return the format information for the provided resource
* @throws IOException
* if an error occurred while reading the resource
*/
@NonNull
FormatDetector.Result detectFormat(@NonNull InputStream is) throws IOException;
/**
* Determine the model of the provided resource.
* <p>
* This method will consume data from any {@link InputStream} provided by the
* {@link InputSource}. If the caller of this method intends to read data from
* the stream after determining the format, the caller should pass in a stream
* that can be reset.
* <p>
* This method will not close any {@link InputStream} provided by the
* {@link InputSource}, since it does not own the stream.
*
* @param is
* an input stream for the resource
* @param format
* the format of the provided resource
* @return the model of the provided resource
* @throws IOException
* if an error occurred while reading the resource
*/
@NonNull
@Owning
ModelDetector.Result detectModel(@NonNull InputStream is, @NonNull Format format) throws IOException;
/**
* Load data from the provided resource into a bound object.
* <p>
* This method will auto-detect the format of the provided resource.
*
* @param <CLASS>
* the type of the bound object to return
* @param file
* the resource
* @return a bound object containing the loaded data
* @throws IOException
* if an error occurred while reading the resource
* @see #detectFormat(File)
*/
@NonNull
default <CLASS extends IBoundObject> CLASS load(@NonNull File file) throws IOException {
return load(ObjectUtils.notNull(file.toPath()));
}
/**
* Load data from the provided resource into a bound object.
* <p>
* This method will auto-detect the format of the provided resource.
*
* @param <CLASS>
* the type of the bound object to return
* @param path
* the resource
* @return a bound object containing the loaded data
* @throws IOException
* if an error occurred while reading the resource
* @see #detectFormat(File)
*/
@NonNull
default <CLASS extends IBoundObject> CLASS load(@NonNull Path path) throws IOException {
return load(ObjectUtils.notNull(path.toUri()));
}
/**
* Load data from the provided resource into a bound object.
* <p>
* This method will auto-detect the format of the provided resource.
*
* @param <CLASS>
* the type of the bound object to return
* @param url
* the resource
* @return a bound object containing the loaded data
* @throws IOException
* if an error occurred while reading the resource
* @throws URISyntaxException
* if the provided {@code url} is malformed
* @see #detectFormat(URL)
*/
@NonNull
default <CLASS extends IBoundObject> CLASS load(@NonNull URL url) throws IOException, URISyntaxException {
return load(ObjectUtils.notNull(url.toURI()));
}
/**
* Load data from the resource identified by the provided {@code uri} into a
* bound object.
* <p>
* This method will auto-detect the format of the provided resource.
*
* @param <CLASS>
* the type of the bound object to return
* @param uri
* the resource
* @return a bound object containing the loaded data
* @throws IOException
* if an error occurred while reading the resource
* @see #detectFormat(URL)
*/
@NonNull
<CLASS extends IBoundObject> CLASS load(@NonNull URI uri) throws IOException;
/**
* Load data from the provided resource into a bound object.
* <p>
* This method should auto-detect the format of the provided resource.
* <p>
* This method will not close the provided {@link InputStream}, since it does
* not own the stream.
*
* @param <CLASS>
* the type of the bound object to return
* @param is
* the resource stream
* @param documentUri
* the URI of the resource
* @return a bound object containing the loaded data
* @throws IOException
* if an error occurred while reading the resource
* @see #detectFormat(InputStream)
*/
@NonNull
<CLASS extends IBoundObject> CLASS load(@NonNull InputStream is, @NonNull URI documentUri) throws IOException;
/**
* Load data from the specified resource into a bound object with the type of
* the specified Java class.
*
* @param <CLASS>
* the Java type to load data into
* @param clazz
* the class for the java type
* @param file
* the resource to load
* @return the loaded instance data
* @throws IOException
* if an error occurred while loading the data in the specified file
*/
@NonNull
default <CLASS extends IBoundObject> CLASS load(
@NonNull Class<CLASS> clazz,
@NonNull File file) throws IOException {
return load(clazz, ObjectUtils.notNull(file.toPath()));
}
/**
* Load data from the specified resource into a bound object with the type of
* the specified Java class.
*
* @param <CLASS>
* the Java type to load data into
* @param clazz
* the class for the java type
* @param path
* the resource to load
* @return the loaded instance data
* @throws IOException
* if an error occurred while loading the data in the specified file
*/
@NonNull
default <CLASS extends IBoundObject> CLASS load(
@NonNull Class<CLASS> clazz,
@NonNull Path path) throws IOException {
return load(clazz, ObjectUtils.notNull(path.toUri()));
}
/**
* Load data from the specified resource into a bound object with the type of
* the specified Java class.
*
* @param <CLASS>
* the Java type to load data into
* @param clazz
* the class for the java type
* @param url
* the resource to load
* @return the loaded instance data
* @throws IOException
* if an error occurred while loading the data in the specified file
* @throws URISyntaxException
* if the provided {@code url} is malformed
*/
@NonNull
default <CLASS extends IBoundObject> CLASS load(
@NonNull Class<CLASS> clazz,
@NonNull URL url) throws IOException, URISyntaxException {
return load(clazz, ObjectUtils.notNull(url.toURI()));
}
/**
* Load data from the specified resource into a bound object with the type of
* the specified Java class.
*
* @param <CLASS>
* the Java type to load data into
* @param clazz
* the class for the java type
* @param uri
* the resource to load
* @return the loaded instance data
* @throws IOException
* if an error occurred while loading the data in the specified file
*/
@NonNull
<CLASS extends IBoundObject> CLASS load(
@NonNull Class<CLASS> clazz,
@NonNull URI uri) throws IOException;
/**
* Load data from the specified resource into a bound object with the type of
* the specified Java class.
* <p>
* This method will not close the provided {@link InputStream}, since it does
* not own the stream.
* <p>
* Implementations of this method will do format detection. This process might
* leave the provided {@link InputStream} at a position beyond the last parsed
* location. If you want to avoid this possibility, use and implementation of
* {@link IDeserializer#deserialize(InputStream, URI)} instead, such as what is
* provided by {@link DefaultBindingContext#newDeserializer(Format, Class)}.
*
* @param <CLASS>
* the Java type to load data into
* @param clazz
* the class for the java type
* @param is
* the resource stream
* @param documentUri
* the URI of the resource
* @return the loaded data
* @throws IOException
* if an error occurred while loading the data from the specified
* resource
*/
@NonNull
<CLASS extends IBoundObject> CLASS load(
@NonNull Class<CLASS> clazz,
@NonNull InputStream is,
@NonNull URI documentUri) throws IOException;
/**
* Load data from the specified resource into a bound object with the type of
* the specified Java class.
* <p>
* This method will not close the provided {@link InputStream}, since it does
* not own the stream.
*
* @param <CLASS>
* the Java type to load data into
* @param format
* the format to parse
* @param clazz
* the class for the java type
* @param is
* the resource stream
* @param documentUri
* the URI of the resource
* @return the loaded data
* @throws IOException
* if an error occurred while loading the data from the specified
* resource
*/
@NonNull
<CLASS extends IBoundObject> CLASS load(
@NonNull Class<CLASS> clazz,
@NonNull Format format,
@NonNull InputStream is,
@NonNull URI documentUri) throws IOException;
/**
* Load data expressed using the provided {@code format} and return that data as
* a Metapath node item.
* <p>
* The specific Module model is auto-detected by analyzing the source. The class
* reported is implementation specific.
*
* @param format
* the expected format of the data to parse
* @param path
* the resource
* @return the Metapath node item for the parsed data
* @throws IOException
* if an error occurred while loading the data from the specified
* resource
*/
@NonNull
default IDocumentNodeItem loadAsNodeItem(
@NonNull Format format,
@NonNull Path path) throws IOException {
return loadAsNodeItem(format, ObjectUtils.notNull(path.toUri()));
}
/**
* Load data expressed using the provided {@code format} and return that data as
* a Metapath node item.
* <p>
* The specific Module model is auto-detected by analyzing the source. The class
* reported is implementation specific.
*
* @param format
* the expected format of the data to parse
* @param uri
* the resource
* @return the Metapath node item for the parsed data
* @throws IOException
* if an error occurred while loading the data from the specified
* resource
*/
@NonNull
IDocumentNodeItem loadAsNodeItem(
@NonNull Format format,
@NonNull URI uri) throws IOException;
/**
* Load data expressed using the provided {@code format} and return that data as
* a Metapath node item.
* <p>
* The specific Module model is auto-detected by analyzing the source. The class
* reported is implementation specific.
*
* @param format
* the expected format of the data to parse
* @param is
* the resource stream
* @param documentUri
* the URI of the resource
* @return the Metapath node item for the parsed data
* @throws IOException
* if an error occurred while loading the data from the specified
* resource
*/
@NonNull
IDocumentNodeItem loadAsNodeItem(
@NonNull Format format,
@NonNull InputStream is,
@NonNull URI documentUri) throws IOException;
/**
* Get the configured Module binding context to use to load Java types.
*
* @return the binding context
*/
@NonNull
IBindingContext getBindingContext();
/**
* Auto convert the provided {@code source} to the provided {@code toFormat}.
* Write the converted content to the provided {@code destination}.
* <p>
* The format of the source is expected to be auto detected using
* {@link #detectFormat(Path)}.
*
* @param <CLASS>
* the Java type to load data into
* @param source
* the resource to convert
* @param destination
* the resource to write converted content to
* @param toFormat
* the format to convert to
* @param rootClass
* the class for the Java type to load data into
* @throws FileNotFoundException
* the the provided source file was not found
* @throws IOException
* if an error occurred while loading the data from the specified
* resource or writing the converted data to the specified destination
*/
default <CLASS extends IBoundObject> void convert(
@NonNull Path source,
@NonNull Path destination,
@NonNull Format toFormat,
@NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
CLASS object = load(rootClass, source);
ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
serializer.serialize(object, destination);
}
/**
* Auto convert the provided {@code source} to the provided {@code toFormat}.
* Write the converted content to the provided {@code destination}.
* <p>
* The format of the source is expected to be auto detected using
* {@link #detectFormat(Path)}.
*
* @param <CLASS>
* the Java type to load data into
* @param source
* the resource to convert
* @param os
* the output stream to write converted content to
* @param toFormat
* the format to convert to
* @param rootClass
* the class for the Java type to load data into
* @throws FileNotFoundException
* the the provided source file was not found
* @throws IOException
* if an error occurred while loading the data from the specified
* resource or writing the converted data to the specified destination
*/
default <CLASS extends IBoundObject> void convert(
@NonNull Path source,
@NonNull OutputStream os,
@NonNull Format toFormat,
@NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
CLASS object = load(rootClass, source);
ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
serializer.serialize(object, os);
}
/**
* Auto convert the provided {@code source} to the provided {@code toFormat}.
* Write the converted content to the provided {@code destination}.
* <p>
* The format of the source is expected to be auto detected using
* {@link #detectFormat(Path)}.
*
* @param <CLASS>
* the Java type to load data into
* @param source
* the resource to convert
* @param destination
* the resource to write converted content to
* @param toFormat
* the format to convert to
* @param rootClass
* the class for the Java type to load data into
* @throws FileNotFoundException
* the the provided source file was not found
* @throws IOException
* if an error occurred while loading the data from the specified
* resource or writing the converted data to the specified destination
*/
default <CLASS extends IBoundObject> void convert(
@NonNull URI source,
@NonNull Path destination,
@NonNull Format toFormat,
@NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
CLASS object = load(rootClass, source);
ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
serializer.serialize(object, destination);
}
/**
* Auto convert the provided {@code source} to the provided {@code toFormat}.
* Write the converted content to the provided {@code destination}.
* <p>
* The format of the source is expected to be auto detected using
* {@link #detectFormat(Path)}.
*
* @param <CLASS>
* the Java type to load data into
* @param source
* the resource to convert
* @param os
* the output stream to write converted content to
* @param toFormat
* the format to convert to
* @param rootClass
* the class for the Java type to load data into
* @throws FileNotFoundException
* the the provided source file was not found
* @throws IOException
* if an error occurred while loading the data from the specified
* resource or writing the converted data to the specified destination
*/
default <CLASS extends IBoundObject> void convert(
@NonNull URI source,
@NonNull OutputStream os,
@NonNull Format toFormat,
@NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
CLASS object = load(rootClass, source);
ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
serializer.serialize(object, os);
}
/**
* Auto convert the provided {@code source} to the provided {@code toFormat}.
* Write the converted content to the provided {@code destination}.
* <p>
* The format of the source is expected to be auto detected using
* {@link #detectFormat(Path)}.
*
* @param <CLASS>
* the Java type to load data into
* @param source
* the resource to convert
* @param writer
* the writer to write converted content to
* @param toFormat
* the format to convert to
* @param rootClass
* the class for the Java type to load data into
* @throws FileNotFoundException
* the the provided source file was not found
* @throws IOException
* if an error occurred while loading the data from the specified
* resource or writing the converted data to the specified destination
*/
default <CLASS extends IBoundObject> void convert(
@NonNull URI source,
@NonNull Writer writer,
@NonNull Format toFormat,
@NonNull Class<CLASS> rootClass) throws FileNotFoundException, IOException {
CLASS object = load(rootClass, source);
ISerializer<CLASS> serializer = getBindingContext().newSerializer(toFormat, rootClass);
serializer.serialize(object, writer);
}
}