Search in sources :

Example 1 with FactoryDataException

use of org.apache.sis.referencing.factory.FactoryDataException in project sis by apache.

the class ConsistencyTest method testCoordinateReferenceSystems.

/**
 * Verifies the WKT consistency of all CRS instances.
 *
 * @throws FactoryException if an error other than "unsupported operation method" occurred.
 */
@Test
public void testCoordinateReferenceSystems() throws FactoryException {
    assumeTrue(RUN_EXTENSIVE_TESTS);
    final WKTFormat v1 = new WKTFormat(null, null);
    final WKTFormat v1c = new WKTFormat(null, null);
    final WKTFormat v2 = new WKTFormat(null, null);
    final WKTFormat v2s = new WKTFormat(null, null);
    v1.setConvention(Convention.WKT1);
    v1c.setConvention(Convention.WKT1_COMMON_UNITS);
    v2.setConvention(Convention.WKT2);
    v2s.setConvention(Convention.WKT2_SIMPLIFIED);
    for (final String code : CRS.getAuthorityFactory(null).getAuthorityCodes(CoordinateReferenceSystem.class)) {
        if (!EXCLUDES.contains(code)) {
            final CoordinateReferenceSystem crs;
            try {
                crs = CRS.forCode(code);
            } catch (UnavailableFactoryException | NoSuchIdentifierException | FactoryDataException e) {
                print(code, "WARNING", e.getLocalizedMessage());
                continue;
            }
            lookup(parseAndFormat(v2, code, crs), crs);
            lookup(parseAndFormat(v2s, code, crs), crs);
            /*
                 * There is more information lost in WKT 1 than in WKT 2, so we can not test everything.
                 * For example we can not format fully three-dimensional geographic CRS because the unit
                 * is not the same for all axes. We can not format neither some axis directions.
                 */
            try {
                parseAndFormat(v1, code, crs);
            } catch (UnformattableObjectException e) {
                print(code, "WARNING", e.getLocalizedMessage());
                continue;
            }
            parseAndFormat(v1c, code, crs);
        }
    }
}
Also used : UnformattableObjectException(org.apache.sis.io.wkt.UnformattableObjectException) FactoryDataException(org.apache.sis.referencing.factory.FactoryDataException) NoSuchIdentifierException(org.opengis.util.NoSuchIdentifierException) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) UnavailableFactoryException(org.apache.sis.referencing.factory.UnavailableFactoryException) WKTFormat(org.apache.sis.io.wkt.WKTFormat) Test(org.junit.Test)

Example 2 with FactoryDataException

use of org.apache.sis.referencing.factory.FactoryDataException in project sis by apache.

the class EPSGDataAccess method fillParameterValues.

/**
 * Sets the values of all parameters in the given group.
 *
 * @param  method      the EPSG code for the operation method.
 * @param  operation   the EPSG code for the operation (conversion or transformation).
 * @param  parameters  the parameter values to fill.
 * @throws SQLException if a SQL statement failed.
 */
private void fillParameterValues(final Integer method, final Integer operation, final ParameterValueGroup parameters) throws FactoryException, SQLException {
    try (ResultSet result = executeQuery("Coordinate_Operation Parameter Value", "SELECT CP.PARAMETER_NAME," + " CV.PARAMETER_VALUE," + " CV.PARAM_VALUE_FILE_REF," + " CV.UOM_CODE" + " FROM ([Coordinate_Operation Parameter Value] AS CV" + " INNER JOIN [Coordinate_Operation Parameter] AS CP" + " ON CV.PARAMETER_CODE = CP.PARAMETER_CODE)" + " INNER JOIN [Coordinate_Operation Parameter Usage] AS CU" + " ON (CP.PARAMETER_CODE = CU.PARAMETER_CODE)" + " AND (CV.COORD_OP_METHOD_CODE = CU.COORD_OP_METHOD_CODE)" + " WHERE CV.COORD_OP_METHOD_CODE = ?" + " AND CV.COORD_OP_CODE = ?" + " ORDER BY CU.SORT_ORDER", method, operation)) {
        while (result.next()) {
            final String name = getString(operation, result, 1);
            final double value = getOptionalDouble(result, 2);
            final Unit<?> unit;
            String reference;
            if (Double.isNaN(value)) {
                /*
                     * If no numeric values were provided in the database, then the values should be
                     * in some external file. It may be a file in the $SIS_DATA/DatumChanges directory.
                     */
                reference = getString(operation, result, 3);
                unit = null;
            } else {
                reference = null;
                final String unitCode = getOptionalString(result, 4);
                unit = (unitCode != null) ? owner.createUnit(unitCode) : null;
            }
            final ParameterValue<?> param;
            try {
                param = parameters.parameter(name);
            } catch (ParameterNotFoundException exception) {
                /*
                     * Wrap the unchecked ParameterNotFoundException into the checked NoSuchIdentifierException,
                     * which is a FactoryException subclass.  Note that in principle, NoSuchIdentifierException is for
                     * MathTransforms rather than parameters. However we are close in spirit here since we are setting
                     * up MathTransform's parameters. Using NoSuchIdentifierException allows CoordinateOperationSet to
                     * know that the failure is probably caused by a MathTransform not yet supported in Apache SIS
                     * (or only partially supported) rather than some more serious failure in the database side.
                     * Callers can use this information in order to determine if they should try the next coordinate
                     * operation or propagate the exception.
                     */
                throw (NoSuchIdentifierException) new NoSuchIdentifierException(error().getString(Errors.Keys.CanNotSetParameterValue_1, name), name).initCause(exception);
            }
            try {
                if (reference != null) {
                    param.setValue(reference);
                } else if (unit != null) {
                    param.setValue(value, unit);
                } else {
                    param.setValue(value);
                }
            } catch (RuntimeException exception) {
                // Catch InvalidParameterValueException, ArithmeticException and others.
                throw new FactoryDataException(error().getString(Errors.Keys.CanNotSetParameterValue_1, name), exception);
            }
        }
    }
}
Also used : FactoryDataException(org.apache.sis.referencing.factory.FactoryDataException) ResultSet(java.sql.ResultSet) NoSuchIdentifierException(org.opengis.util.NoSuchIdentifierException) InternationalString(org.opengis.util.InternationalString) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString) ParameterNotFoundException(org.opengis.parameter.ParameterNotFoundException)

Example 3 with FactoryDataException

use of org.apache.sis.referencing.factory.FactoryDataException in project sis by apache.

the class EPSGDataAccess method createUnit.

/**
 * Creates an unit of measurement from a code.
 * Current implementation first checks if {@link Units#valueOfEPSG(int)} can provide a hard-coded unit
 * for the given code before to try to parse the information found in the database. This is done that
 * way for better support of non-straightforward units like <cite>sexagesimal degrees</cite>
 * (EPSG:9110 and 9111).
 *
 * <div class="note"><b>Example:</b>
 * some EPSG codes for units are:
 *
 * <table class="sis" summary="EPSG codes examples">
 *   <tr><th>Code</th> <th>Description</th></tr>
 *   <tr><td>9002</td> <td>decimal degree</td></tr>
 *   <tr><td>9001</td> <td>metre</td></tr>
 *   <tr><td>9030</td> <td>kilometre</td></tr>
 *   <tr><td>1040</td> <td>second</td></tr>
 *   <tr><td>1029</td> <td>year</td></tr>
 * </table></div>
 *
 * @param  code  value allocated by EPSG.
 * @return the unit of measurement for the given code.
 * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
 * @throws FactoryException if the object creation failed for some other reason.
 */
@Override
public synchronized Unit<?> createUnit(final String code) throws NoSuchAuthorityCodeException, FactoryException {
    ArgumentChecks.ensureNonNull("code", code);
    Unit<?> returnValue = null;
    try (ResultSet result = executeQuery("Unit of Measure", "UOM_CODE", "UNIT_OF_MEAS_NAME", "SELECT UOM_CODE," + " FACTOR_B," + " FACTOR_C," + " TARGET_UOM_CODE," + " UNIT_OF_MEAS_NAME" + " FROM [Unit of Measure]" + " WHERE UOM_CODE = ?", code)) {
        while (result.next()) {
            final int source = getInteger(code, result, 1);
            final double b = getOptionalDouble(result, 2);
            final double c = getOptionalDouble(result, 3);
            final int target = getInteger(code, result, 4);
            if (source == target) {
                /*
                     * The unit is a base unit. Verify its consistency:
                     * conversion from 'source' to itself shall be the identity function.
                     */
                final boolean pb = (b != 1);
                if (pb || c != 1) {
                    throw new FactoryDataException(error().getString(Errors.Keys.InconsistentAttribute_2, pb ? "FACTOR_B" : "FACTOR_C", pb ? b : c));
                }
            }
            // Check in our list of hard-coded unit codes.
            Unit<?> unit = Units.valueOfEPSG(source);
            if (unit == null) {
                final Unit<?> base = Units.valueOfEPSG(target);
                if (base != null && !Double.isNaN(b) && !Double.isNaN(c)) {
                    // May be NaN if the conversion is non-linear.
                    unit = Units.multiply(base, b, c);
                } else
                    try {
                        // Try parsing the unit symbol as a fallback.
                        unit = Units.valueOf(getString(code, result, 5));
                    } catch (ParserException e) {
                        throw new FactoryDataException(error().getString(Errors.Keys.UnknownUnit_1, code), e);
                    }
            }
            returnValue = ensureSingleton(unit, returnValue, code);
        }
    } catch (SQLException exception) {
        throw databaseFailure(Unit.class, code, exception);
    }
    if (returnValue == null) {
        throw noSuchAuthorityCode(Unit.class, code);
    }
    return returnValue;
}
Also used : ParserException(javax.measure.format.ParserException) FactoryDataException(org.apache.sis.referencing.factory.FactoryDataException) SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) Unit(javax.measure.Unit)

Example 4 with FactoryDataException

use of org.apache.sis.referencing.factory.FactoryDataException in project sis by apache.

the class EPSGDataAccess method createDatum.

/**
 * Creates an arbitrary datum from a code. The returned object will typically be an
 * instance of {@link GeodeticDatum}, {@link VerticalDatum} or {@link TemporalDatum}.
 *
 * <div class="note"><b>Example:</b>
 * some EPSG codes for datums are:
 *
 * <table class="sis" summary="EPSG codes examples">
 *   <tr><th>Code</th> <th>Type</th>        <th>Description</th></tr>
 *   <tr><td>6326</td> <td>Geodetic</td>    <td>World Geodetic System 1984</td></tr>
 *   <tr><td>6322</td> <td>Geodetic</td>    <td>World Geodetic System 1972</td></tr>
 *   <tr><td>1027</td> <td>Vertical</td>    <td>EGM2008 geoid</td></tr>
 *   <tr><td>5100</td> <td>Vertical</td>    <td>Mean Sea Level</td></tr>
 *   <tr><td>9315</td> <td>Engineering</td> <td>Seismic bin grid datum</td></tr>
 * </table></div>
 *
 * @param  code  value allocated by EPSG.
 * @return the datum for the given code.
 * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
 * @throws FactoryException if the object creation failed for some other reason.
 */
@Override
public synchronized Datum createDatum(final String code) throws NoSuchAuthorityCodeException, FactoryException {
    ArgumentChecks.ensureNonNull("code", code);
    Datum returnValue = null;
    try (ResultSet result = executeQuery("Datum", "DATUM_CODE", "DATUM_NAME", "SELECT DATUM_CODE," + " DATUM_NAME," + " DATUM_TYPE," + " ORIGIN_DESCRIPTION," + " REALIZATION_EPOCH," + " AREA_OF_USE_CODE," + " DATUM_SCOPE," + " REMARKS," + " DEPRECATED," + // Only for geodetic type
    " ELLIPSOID_CODE," + // Only for geodetic type
    " PRIME_MERIDIAN_CODE" + " FROM [Datum]" + " WHERE DATUM_CODE = ?", code)) {
        while (result.next()) {
            final Integer epsg = getInteger(code, result, 1);
            final String name = getString(code, result, 2);
            final String type = getString(code, result, 3);
            final String anchor = getOptionalString(result, 4);
            final String epoch = getOptionalString(result, 5);
            final String area = getOptionalString(result, 6);
            final String scope = getOptionalString(result, 7);
            final String remarks = getOptionalString(result, 8);
            final boolean deprecated = getOptionalBoolean(result, 9);
            Map<String, Object> properties = createProperties("Datum", name, epsg, area, scope, remarks, deprecated);
            if (anchor != null) {
                properties.put(Datum.ANCHOR_POINT_KEY, anchor);
            }
            if (epoch != null)
                try {
                    /*
                     * Parse the date manually because it is declared as a VARCHAR instead than DATE in original
                     * SQL scripts. Apache SIS installer replaces VARCHAR by DATE, but we have no guarantee that
                     * we are reading an EPSG database created by our installer. Furthermore an older version of
                     * EPSG installer was using SMALLINT instead than DATE, because scripts before EPSG 9.0 were
                     * reporting only the epoch year.
                     */
                    final CharSequence[] fields = CharSequences.split(epoch, '-');
                    int year = 0, month = 0, day = 1;
                    for (int i = Math.min(fields.length, 3); --i >= 0; ) {
                        final int f = Integer.parseInt(fields[i].toString());
                        switch(i) {
                            case 0:
                                year = f;
                                break;
                            case 1:
                                month = f - 1;
                                break;
                            case 2:
                                day = f;
                                break;
                        }
                    }
                    if (year != 0) {
                        final Calendar calendar = getCalendar();
                        calendar.set(year, month, day);
                        properties.put(Datum.REALIZATION_EPOCH_KEY, calendar.getTime());
                    }
                } catch (NumberFormatException exception) {
                    // Not a fatal error.
                    unexpectedException("createDatum", exception);
                }
            /*
                 * The following switch statement should have a case for all "epsg_datum_kind" values enumerated
                 * in the "EPSG_Prepare.sql" file, except that the values in this Java code are in lower cases.
                 */
            final DatumFactory datumFactory = owner.datumFactory;
            final Datum datum;
            switch(type.toLowerCase(Locale.US)) {
                /*
                     * The "geodetic" case invokes createProperties(…) indirectly through calls to
                     * createEllipsoid(String) and createPrimeMeridian(String), so we must protect
                     * the properties map from changes.
                     */
                case "geodetic":
                    {
                        // Protect from changes
                        properties = new HashMap<>(properties);
                        final Ellipsoid ellipsoid = owner.createEllipsoid(getString(code, result, 10));
                        final PrimeMeridian meridian = owner.createPrimeMeridian(getString(code, result, 11));
                        final BursaWolfParameters[] param = createBursaWolfParameters(meridian, epsg);
                        if (param != null) {
                            properties.put(DefaultGeodeticDatum.BURSA_WOLF_KEY, param);
                        }
                        datum = datumFactory.createGeodeticDatum(properties, ellipsoid, meridian);
                        break;
                    }
                /*
                     * Vertical datum type is hard-coded to geoidal. It would be possible to infer other
                     * types by looking at the coordinate system, but it could result in different datum
                     * associated to the same EPSG code.  Since vertical datum type is no longer part of
                     * ISO 19111:2007, it is probably not worth to handle such cases.
                     */
                case "vertical":
                    {
                        datum = datumFactory.createVerticalDatum(properties, VerticalDatumType.GEOIDAL);
                        break;
                    }
                /*
                     * Origin date is stored in ORIGIN_DESCRIPTION field. A column of SQL type
                     * "date" type would have been better, but we do not modify the EPSG model.
                     */
                case "temporal":
                    {
                        final Date originDate;
                        if (anchor == null || anchor.isEmpty()) {
                            throw new FactoryDataException(resources().getString(Resources.Keys.DatumOriginShallBeDate));
                        }
                        if (dateFormat == null) {
                            dateFormat = new StandardDateFormat();
                            // Use UTC timezone.
                            dateFormat.setCalendar(getCalendar());
                        }
                        try {
                            originDate = dateFormat.parse(anchor);
                        } catch (ParseException e) {
                            throw new FactoryDataException(resources().getString(Resources.Keys.DatumOriginShallBeDate), e);
                        }
                        datum = datumFactory.createTemporalDatum(properties, originDate);
                        break;
                    }
                /*
                     * Straightforward case.
                     */
                case "engineering":
                    {
                        datum = datumFactory.createEngineeringDatum(properties);
                        break;
                    }
                case "parametric":
                    {
                        datum = ReferencingServices.getInstance().createParametricDatum(properties, datumFactory);
                        break;
                    }
                default:
                    {
                        throw new FactoryDataException(error().getString(Errors.Keys.UnknownType_1, type));
                    }
            }
            returnValue = ensureSingleton(datum, returnValue, code);
            if (result.isClosed()) {
                // Because of the recursive call done by createBursaWolfParameters(…).
                break;
            }
        }
    } catch (SQLException exception) {
        throw databaseFailure(Datum.class, code, exception);
    }
    if (returnValue == null) {
        throw noSuchAuthorityCode(Datum.class, code);
    }
    return returnValue;
}
Also used : DefaultGeodeticDatum(org.apache.sis.referencing.datum.DefaultGeodeticDatum) DefaultParametricDatum(org.apache.sis.referencing.datum.DefaultParametricDatum) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) SQLException(java.sql.SQLException) Calendar(java.util.Calendar) InternationalString(org.opengis.util.InternationalString) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString) Date(java.util.Date) FactoryDataException(org.apache.sis.referencing.factory.FactoryDataException) ResultSet(java.sql.ResultSet) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) IdentifiedObject(org.opengis.referencing.IdentifiedObject) ParseException(java.text.ParseException) StandardDateFormat(org.apache.sis.internal.util.StandardDateFormat)

Example 5 with FactoryDataException

use of org.apache.sis.referencing.factory.FactoryDataException in project sis by apache.

the class EPSGDataAccess method createEllipsoid.

/**
 * Creates a geometric figure that can be used to describe the approximate shape of the earth.
 * In mathematical terms, it is a surface formed by the rotation of an ellipse about its minor axis.
 *
 * <div class="note"><b>Example:</b>
 * some EPSG codes for ellipsoids are:
 *
 * <table class="sis" summary="EPSG codes examples">
 *   <tr><th>Code</th> <th>Description</th></tr>
 *   <tr><td>7030</td> <td>WGS 84</td></tr>
 *   <tr><td>7034</td> <td>Clarke 1880</td></tr>
 *   <tr><td>7048</td> <td>GRS 1980 Authalic Sphere</td></tr>
 * </table></div>
 *
 * @param  code  value allocated by EPSG.
 * @return the ellipsoid for the given code.
 * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
 * @throws FactoryException if the object creation failed for some other reason.
 *
 * @see #createGeodeticDatum(String)
 * @see #createEllipsoidalCS(String)
 * @see org.apache.sis.referencing.datum.DefaultEllipsoid
 */
@Override
public synchronized Ellipsoid createEllipsoid(final String code) throws NoSuchAuthorityCodeException, FactoryException {
    ArgumentChecks.ensureNonNull("code", code);
    Ellipsoid returnValue = null;
    try (ResultSet result = executeQuery("Ellipsoid", "ELLIPSOID_CODE", "ELLIPSOID_NAME", "SELECT ELLIPSOID_CODE," + " ELLIPSOID_NAME," + " SEMI_MAJOR_AXIS," + " INV_FLATTENING," + " SEMI_MINOR_AXIS," + " UOM_CODE," + " REMARKS," + " DEPRECATED" + " FROM [Ellipsoid]" + " WHERE ELLIPSOID_CODE = ?", code)) {
        while (result.next()) {
            /*
                 * One of 'semiMinorAxis' and 'inverseFlattening' values can be NULL in the database.
                 * Consequently, we don't use 'getString(ResultSet, int)' for those parameters because
                 * we do not want to thrown an exception if a NULL value is found.
                 */
            final Integer epsg = getInteger(code, result, 1);
            final String name = getString(code, result, 2);
            final double semiMajorAxis = getDouble(code, result, 3);
            final double inverseFlattening = getOptionalDouble(result, 4);
            final double semiMinorAxis = getOptionalDouble(result, 5);
            final String unitCode = getString(code, result, 6);
            final String remarks = getOptionalString(result, 7);
            final boolean deprecated = getOptionalBoolean(result, 8);
            final Unit<Length> unit = owner.createUnit(unitCode).asType(Length.class);
            final Map<String, Object> properties = createProperties("Ellipsoid", name, epsg, remarks, deprecated);
            final Ellipsoid ellipsoid;
            if (Double.isNaN(inverseFlattening)) {
                if (Double.isNaN(semiMinorAxis)) {
                    // Both are null, which is not allowed.
                    final String column = result.getMetaData().getColumnName(3);
                    throw new FactoryDataException(error().getString(Errors.Keys.NullValueInTable_3, code, column));
                } else {
                    // We only have semiMinorAxis defined. It is OK
                    ellipsoid = owner.datumFactory.createEllipsoid(properties, semiMajorAxis, semiMinorAxis, unit);
                }
            } else {
                if (!Double.isNaN(semiMinorAxis)) {
                    // Both 'inverseFlattening' and 'semiMinorAxis' are defined.
                    // Log a warning and create the ellipsoid using the inverse flattening.
                    final LogRecord record = resources().getLogRecord(Level.WARNING, Resources.Keys.AmbiguousEllipsoid_1, Constants.EPSG + DefaultNameSpace.DEFAULT_SEPARATOR + code);
                    record.setLoggerName(Loggers.CRS_FACTORY);
                    Logging.log(EPSGDataAccess.class, "createEllipsoid", record);
                }
                ellipsoid = owner.datumFactory.createFlattenedSphere(properties, semiMajorAxis, inverseFlattening, unit);
            }
            returnValue = ensureSingleton(ellipsoid, returnValue, code);
        }
    } catch (SQLException exception) {
        throw databaseFailure(Ellipsoid.class, code, exception);
    }
    if (returnValue == null) {
        throw noSuchAuthorityCode(Ellipsoid.class, code);
    }
    return returnValue;
}
Also used : SQLException(java.sql.SQLException) InternationalString(org.opengis.util.InternationalString) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString) FactoryDataException(org.apache.sis.referencing.factory.FactoryDataException) Length(javax.measure.quantity.Length) LogRecord(java.util.logging.LogRecord) ResultSet(java.sql.ResultSet) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) IdentifiedObject(org.opengis.referencing.IdentifiedObject)

Aggregations

FactoryDataException (org.apache.sis.referencing.factory.FactoryDataException)10 ResultSet (java.sql.ResultSet)9 SimpleInternationalString (org.apache.sis.util.iso.SimpleInternationalString)8 InternationalString (org.opengis.util.InternationalString)8 SQLException (java.sql.SQLException)7 AbstractIdentifiedObject (org.apache.sis.referencing.AbstractIdentifiedObject)4 IdentifiedObject (org.opengis.referencing.IdentifiedObject)4 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 DefaultGeodeticDatum (org.apache.sis.referencing.datum.DefaultGeodeticDatum)2 DefaultParametricDatum (org.apache.sis.referencing.datum.DefaultParametricDatum)2 NoSuchIdentifierException (org.opengis.util.NoSuchIdentifierException)2 PreparedStatement (java.sql.PreparedStatement)1 ParseException (java.text.ParseException)1 Calendar (java.util.Calendar)1 Date (java.util.Date)1 Map (java.util.Map)1 LogRecord (java.util.logging.LogRecord)1 Unit (javax.measure.Unit)1 ParserException (javax.measure.format.ParserException)1