001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.metaschema.databind.io; 028 029import gov.nist.secauto.metaschema.core.configuration.IConfiguration; 030import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration; 031import gov.nist.secauto.metaschema.core.metapath.IDocumentLoader; 032import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; 033import gov.nist.secauto.metaschema.core.util.ObjectUtils; 034import gov.nist.secauto.metaschema.databind.DefaultBindingContext; 035import gov.nist.secauto.metaschema.databind.IBindingContext; 036 037import java.io.File; 038import java.io.FileNotFoundException; 039import java.io.IOException; 040import java.io.InputStream; 041import java.io.OutputStream; 042import java.net.URI; 043import java.net.URISyntaxException; 044import java.net.URL; 045import java.nio.file.Path; 046 047import edu.umd.cs.findbugs.annotations.NonNull; 048 049/** 050 * A common interface for loading Module based instance resources. 051 */ 052public interface IBoundLoader extends IDocumentLoader, IMutableConfiguration<DeserializationFeature<?>> { 053 054 @Override 055 default IBoundLoader enableFeature(DeserializationFeature<?> feature) { 056 return set(feature, true); 057 } 058 059 @Override 060 default IBoundLoader disableFeature(DeserializationFeature<?> feature) { 061 return set(feature, false); 062 } 063 064 @Override 065 IBoundLoader applyConfiguration(IConfiguration<DeserializationFeature<?>> other); 066 067 @Override 068 IBoundLoader set(DeserializationFeature<?> feature, Object value); 069 070 /** 071 * Determine the format of the provided resource. 072 * 073 * @param file 074 * the resource 075 * @return the format information for the provided resource 076 * @throws IOException 077 * if an error occurred while reading the resource 078 */ 079 @NonNull 080 default FormatDetector.Result detectFormat(@NonNull File file) throws IOException { 081 return detectFormat(ObjectUtils.notNull(file.toPath())); 082 } 083 084 /** 085 * Determine the format of the provided resource. 086 * 087 * @param path 088 * the resource 089 * @return the format information for the provided resource 090 * @throws IOException 091 * if an error occurred while reading the resource 092 */ 093 @NonNull 094 default FormatDetector.Result detectFormat(@NonNull Path path) throws IOException { 095 return detectFormat(ObjectUtils.notNull(path.toUri())); 096 } 097 098 /** 099 * 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}