use of org.apache.sis.storage.InternalDataStoreException in project sis by apache.
the class Variable method getGridGeometry.
/**
* Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
* Not all variables have a grid geometry. For example collections of features do not have such grid.
* The same grid geometry may be shared by many variables.
* The grid may have fewer {@linkplain Grid#getDimensions() dimensions} than this variable,
* in which case the additional {@linkplain #getGridDimensions() variable dimensions} can be considered as bands.
*
* @return the grid geometry for this variable, or {@code null} if none.
* @throws IOException if an error occurred while reading the data.
* @throws DataStoreException if a logical error occurred.
*/
public final GridGeometry getGridGeometry() throws IOException, DataStoreException {
if (!gridDetermined) {
// Set first so we don't try twice in case of failure.
gridDetermined = true;
final GridMapping gridMapping = GridMapping.forVariable(this);
final GridAdjustment adjustment = new GridAdjustment();
final Grid info = getGrid(adjustment);
if (info != null) {
/*
* This variable may have more dimensions than the grid. We need to reduce the list to the same
* dimensions than the ones in the grid. We can not take Grid.getDimensions() directly because
* those dimensions may not have the same length (this mismatch is handled in the next block).
*/
// In netCDF order.
List<Dimension> dimensions = getGridDimensions();
final int dataDimension = dimensions.size();
if (dataDimension > info.getSourceDimensions()) {
boolean copied = false;
// Also in netCDF order.
final List<Dimension> toKeep = info.getDimensions();
final int numToKeep = toKeep.size();
for (int i = 0; i < numToKeep; i++) {
Dimension expected = toKeep.get(i);
expected = adjustment.gridToVariable.getOrDefault(expected, expected);
/*
* At this point, `expected` is a dimension of the variable that we expect to find at
* current index `i`. If we do not find that dimension, then the unexpected dimension
* is assumed to be a band. We usually remove at most one element. If removal results
* in a list too short, it would be a bug in the way we computed `toKeep`.
*/
while (!expected.equals(dimensions.get(i))) {
if (!copied) {
copied = true;
dimensions = new ArrayList<>(dimensions);
}
/*
* It is possible that we never reach this point if the unexpected dimension is last.
* However in such case the dimension to declare is the last one in netCDF order,
* which corresponds to the first dimension (i.e. dimension 0) in "natural" order.
* Since the `bandDimension` field is initialized to zero, its value is correct.
*/
// Convert netCDF order to "natural" order.
bandDimension = dataDimension - 1 - i;
dimensions.remove(i);
for (int j = dimensions.size(); --j >= i; ) {
dimensions.set(j, dimensions.get(j).decrementIndex());
}
if (dimensions.size() < numToKeep) {
// Should not happen (see above comment).
throw new InternalDataStoreException();
}
}
}
/*
* At this point `dimensions` may still be longer than `toKeep` but it does not matter.
* We only need that for any index i < numToKeep, dimensions.get(i) corresponds to the
* dimension at the same index in the grid.
*/
}
/*
* Compare the size of the variable with the size of the localization grid.
* If they do not match, then there is a scale factor between the two that
* needs to be applied.
*/
GridGeometry grid = info.getGridGeometry(decoder);
if (grid != null) {
if (grid.isDefined(GridGeometry.EXTENT)) {
GridExtent extent = grid.getExtent();
final long[] sizes = new long[extent.getDimension()];
boolean needsResize = false;
for (int i = sizes.length; --i >= 0; ) {
// Convert "natural order" index into netCDF index.
final int d = (sizes.length - 1) - i;
sizes[i] = dimensions.get(d).length();
if (!needsResize) {
needsResize = (sizes[i] != extent.getSize(i));
}
}
if (needsResize) {
final double[] dataToGridIndices = adjustment.dataToGridIndices();
if (dataToGridIndices == null || dataToGridIndices.length < sizes.length) {
warning(Variable.class, "getGridGeometry", Resources.Keys.ResamplingIntervalNotFound_2, getFilename(), getName());
return null;
}
extent = extent.resize(sizes);
grid = GridAdjustment.scale(grid, extent, info.getAnchor(), dataToGridIndices);
}
}
/*
* At this point we finished to build a grid geometry from the information provided by axes.
* If there is grid mapping attributes (e.g. "EPSG_code", "ESRI_pe_string", "GeoTransform",
* "spatial_ref", etc.), substitute some parts of the grid geometry by the parts built from
* those attributes.
*/
if (gridMapping != null) {
grid = gridMapping.adaptGridCRS(this, grid, info.getAnchor());
}
}
gridGeometry = grid;
} else if (gridMapping != null) {
gridGeometry = gridMapping.createGridCRS(this);
}
}
return gridGeometry;
}
use of org.apache.sis.storage.InternalDataStoreException 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.InternalDataStoreException in project sis by apache.
the class Table method setDeferredSearchTables.
/**
* Sets the search tables on all {@link Relation} instances for which this operation has been deferred.
* This happen when a table could not be obtained because of circular dependency.
* This method is invoked after all tables have been created in order to fill such holes.
*
* @param tables all tables created.
*/
final void setDeferredSearchTables(final Analyzer analyzer, final Map<GenericName, Table> tables) throws DataStoreException {
for (final Relation.Direction direction : Relation.Direction.values()) {
final Relation[] relations;
switch(direction) {
case IMPORT:
relations = importedKeys;
break;
case EXPORT:
relations = exportedKeys;
break;
default:
continue;
}
for (final Relation relation : relations) {
if (relation.isSearchTableDeferred()) {
/*
* `ClassCastException` should never occur below because `relation.propertyName` fields
* have been set to association names. If `ClassCastException` occurs here, it is a bug
* in our object constructions.
*/
final DefaultAssociationRole association = (DefaultAssociationRole) featureType.getProperty(relation.propertyName);
final Table table = tables.get(association.getValueType().getName());
if (table == null) {
throw new InternalDataStoreException(association.toString());
}
final PrimaryKey referenced;
switch(direction) {
case IMPORT:
referenced = table.primaryKey;
break;
case EXPORT:
referenced = this.primaryKey;
break;
default:
throw new AssertionError(direction);
}
if (referenced != null) {
relation.setSearchTable(analyzer, table, referenced, direction);
}
}
}
}
}
Aggregations