/**
  * Reads the nodes of a data product and returns an in-memory representation of it.
  *
  * <p>The given subset info can be used to specify spatial and spectral portions of the original
  * proudct. If the subset is omitted, the complete product is read in.
  *
  * <p>Whether the band data - the actual pixel values - is read in immediately or later when
  * pixels are requested, is up to the implementation.
  *
  * @param input an object representing a valid output for this product reader, might be a <code>
  *     ImageInputStream</code> or other <code>Object</code> to use for future decoding.
  * @param subsetDef a spectral or spatial subset (or both) of the product. If <code>null</code>,
  *     the entire product is read in
  * @throws IllegalArgumentException if input type is not supported (see {@link
  *     ProductReaderPlugIn#getInputTypes()}).
  * @throws IOException if an I/O error occurs
  * @throws IllegalFileFormatException if the file format is unknown.
  */
 public Product readProductNodes(Object input, ProductSubsetDef subsetDef) throws IOException {
   // (nf, 26.09.2007) removed (input == null) check, null inputs (= no sources) shall be allowed
   if (input != null && !isInstanceOfValidInputType(input)) {
     throw new IllegalArgumentException("invalid input source: " + input);
   }
   final long startTime = System.currentTimeMillis();
   setInput(input);
   setSubsetDef(subsetDef);
   final Product product = readProductNodesImpl();
   configurePreferredTileSize(product);
   product.setModified(false);
   if (product.getProductReader() == null) {
     product.setProductReader(this);
   }
   final long endTime = System.currentTimeMillis();
   String msg = String.format("Read product nodes (took %d ms)", (endTime - startTime));
   SystemUtils.LOG.fine(msg);
   return product;
 }