use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class GridGeometryInfo method getAxes.
/**
* Returns all axes of the netCDF coordinate system, together with the grid dimension to which the axis
* is associated. See {@code org.apache.sis.internal.netcdf.ucar.GridGeometryWrapper.getAxes()} for a
* closer look on the relationship between this algorithm and the UCAR library.
*
* <p>In this method, the words "domain" and "range" are used in the netCDF sense: they are the input
* (domain) and output (range) of the function that convert grid indices to geodetic coordinates.</p>
*
* <p>The domain of all axes is often the same than the domain of the variable, but not necessarily.
* In particular, the relationship is not straightforward when the coordinate system contains
* "two-dimensional axes" (in {@link ucar.nc2.dataset.CoordinateAxis2D} sense).</p>
*
* @return the CRS axes, in netCDF order (reverse of "natural" order).
* @throws IOException if an I/O operation was necessary but failed.
* @throws DataStoreException if a logical error occurred.
*/
@Override
public Axis[] getAxes() throws IOException, DataStoreException {
/*
* Process the variables in the order the appear in the sequence of bytes that make the netCDF files.
* This is often the same order than the indices, but not necessarily. The intent is to reduce the
* amount of disk seek operations.
*/
final SortedMap<VariableInfo, Integer> variables = new TreeMap<>();
for (int i = 0; i < range.length; i++) {
final VariableInfo v = range[i];
if (variables.put(v, i) != null) {
throw new DataStoreException(Errors.format(Errors.Keys.DuplicatedElement_1, v.getName()));
}
}
/*
* In this method, 'sourceDim' and 'targetDim' are relative to "grid to CRS" conversion.
* So 'sourceDim' is the grid (domain) dimension and 'targetDim' is the CRS (range) dimension.
*/
final Axis[] axes = new Axis[range.length];
for (final SortedMap.Entry<VariableInfo, Integer> entry : variables.entrySet()) {
final int targetDim = entry.getValue();
final VariableInfo axis = entry.getKey();
/*
* The AttributeNames are for ISO 19115 metadata. They are not used for locating grid cells
* on Earth, but we nevertheless get them now for making MetadataReader work easier.
*/
AttributeNames.Dimension attributeNames = null;
final String type = axis.getAxisType();
if (type != null) {
for (int i = 0; i < AXIS_TYPES.length; i += 2) {
if (type.equalsIgnoreCase((String) AXIS_TYPES[i])) {
attributeNames = (AttributeNames.Dimension) AXIS_TYPES[i + 1];
break;
}
}
}
/*
* Get the grid dimensions (part of the "domain" in UCAR terminology) used for computing
* the ordinate values along the current axis. There is exactly 1 such grid dimension in
* straightforward netCDF files. However some more complex files may have 2 dimensions.
*/
int i = 0;
final Dimension[] axisDomain = axis.dimensions;
final int[] indices = new int[axisDomain.length];
final int[] sizes = new int[axisDomain.length];
for (final Dimension dimension : axisDomain) {
for (int sourceDim = domain.length; --sourceDim >= 0; ) {
if (domain[sourceDim] == dimension) {
indices[i] = sourceDim;
sizes[i++] = dimension.length;
break;
}
}
}
axes[targetDim] = new Axis(this, axis, attributeNames, ArraysExt.resize(indices, i), ArraysExt.resize(sizes, i));
}
return axes;
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class LandsatReader method read.
/**
* Parses the metadata from the given characters reader.
* The parsing stop after the first {@code "END"} keyword.
* See class javadoc for more information on the expected format.
*
* @param reader a reader opened on the Landsat file.
* It is caller's responsibility to close this reader.
* @throws IOException if an I/O error occurred while reading the given stream.
* @throws DataStoreException if the content is not a Landsat file.
*/
void read(final BufferedReader reader) throws IOException, DataStoreException {
// Starts the description of a new image.
metadata.newCoverage(true);
String line;
while ((line = reader.readLine()) != null) {
int end = CharSequences.skipTrailingWhitespaces(line, 0, line.length());
int start = CharSequences.skipLeadingWhitespaces(line, 0, end);
if (start < end && line.charAt(start) != '#') {
/*
* Separate the line into its key and value. For example in CORNER_UL_LAT_PRODUCT = 12.61111,
* the key will be CORNER_UL_LAT_PRODUCT and the value will be 12.61111.
*/
final int separator = line.indexOf('=', start);
if (separator < 0) {
/*
* Landsat metadata ends with the END keyword, without value after that keyword.
* If we find it, stop reading. All remaining lines (if any) will be ignored.
*/
if (end - start != END.length() || !line.regionMatches(true, start, END, 0, END.length())) {
throw new DataStoreException(errors().getString(Errors.Keys.NotAKeyValuePair_1, line));
}
return;
}
/*
* If the key ends with "_BAND_" followed by a number, remove the band number from the
* key and parse that number as an integer value. Exemple: "REFLECTANCE_ADD_BAND_1".
* We keep the "_BAND_" suffix in the key for avoiding ambiguity.
*/
String key = line.substring(start, CharSequences.skipTrailingWhitespaces(line, start, separator)).toUpperCase(Locale.US);
int band = 0;
for (int i = key.length(); --i >= 0; ) {
final char c = key.charAt(i);
if (c < '0' || c > '9') {
if (c == '_') {
if (key.regionMatches(i - BAND_SUFFIX.length(), BAND_SUFFIX, 0, BAND_SUFFIX.length()))
try {
band = Integer.parseInt(key.substring(++i));
key = key.substring(0, i);
} catch (NumberFormatException e) {
warning(key, reader, e);
}
}
break;
}
}
/*
* In a Landsat file, String values are between quotes. Example: STATION_ID = "LGN".
* If such quotes are found, remove them.
*/
start = CharSequences.skipLeadingWhitespaces(line, separator + 1, end);
if (end - start >= 2 && line.charAt(start) == '"' && line.charAt(end - 1) == '"') {
start = CharSequences.skipLeadingWhitespaces(line, start + 1, --end);
end = CharSequences.skipTrailingWhitespaces(line, start, end);
}
try {
parseKeyValuePair(key, band, line.substring(start, end));
} catch (IllegalArgumentException | DateTimeException e) {
warning(key, reader, e);
}
}
}
listeners.warning(errors().getString(Errors.Keys.UnexpectedEndOfFile_1, getFilename()), null);
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class VariableWrapper method readArray.
/**
* Reads the data from this variable and returns them as an array of a Java primitive type.
* Multi-dimensional variables are flattened as a one-dimensional array (wrapped in a vector).
* This method may replace fill/missing values by NaN values and caches the returned vector.
*
* @param area indices of cell values to read along each dimension, in "natural" order.
* @param subsampling subsampling along each dimension, or {@code null} if none.
* @return the data as an array of a Java primitive type.
*
* @see #read()
* @see #read(GridExtent, int[])
*/
private Object readArray(final GridExtent area, final int[] subsampling) throws IOException, DataStoreException {
int n = area.getDimension();
final int[] lower = new int[n];
final int[] size = new int[n];
final int[] sub = (subsampling != null) ? new int[n] : null;
n--;
for (int i = 0; i <= n; i++) {
final int j = (n - i);
lower[j] = Math.toIntExact(area.getLow(i));
size[j] = Math.toIntExact(area.getSize(i));
if (sub != null) {
sub[j] = subsampling[i];
}
}
final Array array;
try {
array = variable.read(sub != null ? new Section(lower, size, sub) : new Section(lower, size));
} catch (InvalidRangeException e) {
throw new DataStoreException(e);
}
return get1DJavaArray(array);
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class NetcdfStoreProvider method createByReflection.
/**
* Creates a new netCDF decoder as a wrapper around the UCAR library. This decoder is used only when we can
* not create our embedded netCDF decoder. This method uses reflection for creating the wrapper, in order
* to keep the UCAR dependency optional.
*
* @param input the netCDF file object of filename string from which to read data.
* @param isUCAR {@code true} if {@code input} is an instance of the UCAR {@link ucar.nc2.NetcdfFile} object,
* or {@code false} if it is the filename as a {@code String}.
* @param geomlib the library for geometric objects, or {@code null} for the default.
* @param listeners where to send the warnings.
* @return the {@link DecoderWrapper} instance for the given input, or {@code null} if the input type is not recognized.
* @throws IOException if an error occurred while opening the netCDF file.
* @throws DataStoreException if a logical error (other than I/O) occurred.
*/
private static Decoder createByReflection(final Object input, final boolean isUCAR, final GeometryLibrary geomlib, final StoreListeners listeners) throws IOException, DataStoreException {
ensureInitialized(true);
/*
* Get the appropriate constructor for the isUCAR argument. This constructor will be null
* if the above code failed to load the UCAR library. Otherwise, instantiate the wrapper.
*/
final Constructor<? extends Decoder> constructor;
final Class<?> expectedType;
if (isUCAR) {
constructor = createFromUCAR;
expectedType = netcdfFileClass;
} else {
constructor = createFromPath;
expectedType = String.class;
}
if (constructor == null || !expectedType.isInstance(input)) {
return null;
}
try {
return constructor.newInstance(input, geomlib, listeners);
} catch (InvocationTargetException e) {
final Throwable cause = e.getCause();
if (cause instanceof IOException)
throw (IOException) cause;
if (cause instanceof DataStoreException)
throw (DataStoreException) cause;
if (cause instanceof RuntimeException)
throw (RuntimeException) cause;
if (cause instanceof Error)
throw (Error) cause;
// Should never happen actually.
throw new UndeclaredThrowableException(cause);
} catch (ReflectiveOperationException e) {
// Should never happen (shall be verified by the JUnit tests).
throw new InternalDataStoreException(e);
}
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class NetcdfStoreProvider method probeContent.
/**
* Returns {@link ProbeResult#SUPPORTED} if the given storage appears to be supported by {@link NetcdfStore}.
* Returning {@code SUPPORTED} from this method does not guarantee that reading or writing will succeed,
* only that there appears to be a reasonable chance of success based on a brief inspection of the
* {@linkplain StorageConnector#getStorage() storage object} or contents.
*
* @param connector information about the storage (URL, stream, {@link ucar.nc2.NetcdfFile} instance, <i>etc</i>).
* @return {@code SUPPORTED} if the given storage seems to be usable by {@code NetcdfStore} instances.
* @throws DataStoreException if an I/O error occurred.
*/
@Override
public ProbeResult probeContent(final StorageConnector connector) throws DataStoreException {
int version = 0;
boolean hasVersion = false;
boolean isSupported = false;
ByteBuffer buffer = connector.getStorageAs(ByteBuffer.class);
if (buffer != null) {
if (buffer.remaining() < Integer.BYTES) {
return ProbeResult.INSUFFICIENT_BYTES;
}
// Get a buffer with ByteOrder.BIG_ENDIAN.
buffer = buffer.duplicate();
final int header = buffer.getInt();
if ((header & 0xFFFFFF00) == ChannelDecoder.MAGIC_NUMBER) {
hasVersion = true;
version = header & 0xFF;
isSupported = (version >= 1 && version <= ChannelDecoder.MAX_VERSION);
}
}
/*
* If we failed to check using the embedded decoder, tries using the UCAR library.
* The UCAR library is an optional dependency. If that library is present and the
* input is a String, then the following code may trigs a large amount of classes
* loading.
*
* Note that the UCAR library expects a String argument, not a File, because it
* has special cases for "file:", "http:", "nodods:" and "slurp:" protocols.
*/
if (!isSupported) {
final String path = connector.getStorageAs(String.class);
if (path != null) {
ensureInitialized(false);
final Method method = canOpenFromPath;
if (method != null)
try {
isSupported = (Boolean) method.invoke(null, path);
} catch (IllegalAccessException e) {
// Should never happen, since the method is public.
throw (Error) new IncompatibleClassChangeError("canOpen").initCause(e);
} catch (InvocationTargetException e) {
final Throwable cause = e.getCause();
if (cause instanceof DataStoreException) {
throw (DataStoreException) cause;
} else if (cause instanceof IOException) {
/*
* Happen if the String argument uses any protocol not recognized by the UCAR library,
* in which case UCAR tries to open it as a file even if it is not a file. For example
* we get this exception for "jar:file:/file.jar!/entry.nc".
*/
Logging.recoverableException(getLogger(), NetcdfStoreProvider.class, "probeContent", cause);
return ProbeResult.UNSUPPORTED_STORAGE;
}
throw new CanNotProbeException(this, connector, cause);
}
} else {
/*
* Check if the given input is itself an instance of the UCAR oject.
* We check classnames instead of netcdfFileClass.isInstance(storage)
* in order to avoid loading the UCAR library if not needed.
*/
for (Class<?> type = connector.getStorage().getClass(); type != null; type = type.getSuperclass()) {
if (UCAR_CLASSNAME.equals(type.getName())) {
isSupported = true;
break;
}
}
}
}
/*
* At this point, the readability status has been determined. The file version number
* is unknown if we are able to open the file only through the UCAR library.
*/
if (hasVersion) {
return new ProbeResult(isSupported, MIME_TYPE, Version.valueOf(version));
}
return isSupported ? new ProbeResult(true, MIME_TYPE, null) : ProbeResult.UNSUPPORTED_STORAGE;
}
Aggregations