public synchronized CoordinateOperation createCoordinateOperation()

in endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java [2796:2997]


    public synchronized CoordinateOperation createCoordinateOperation(final String code)
            throws NoSuchAuthorityCodeException, FactoryException
    {
        ArgumentChecks.ensureNonNull("code", code);
        CoordinateOperation returnValue = null;
        try {
            try (ResultSet result = executeQuery("Coordinate_Operation", "COORD_OP_CODE", "COORD_OP_NAME",
                    "SELECT COORD_OP_CODE," +
                          " COORD_OP_NAME," +
                          " COORD_OP_TYPE," +
                          " SOURCE_CRS_CODE," +
                          " TARGET_CRS_CODE," +
                          " COORD_OP_METHOD_CODE," +
                          " COORD_TFM_VERSION," +
                          " COORD_OP_ACCURACY," +
                          " AREA_OF_USE_CODE," +
                          " COORD_OP_SCOPE," +
                          " REMARKS," +
                          " DEPRECATED" +
                    " FROM [Coordinate_Operation]" +
                    " WHERE COORD_OP_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).toLowerCase(Locale.US);
                    final boolean isTransformation = type.equals("transformation");
                    final boolean isConversion     = type.equals("conversion");
                    final boolean isConcatenated   = type.equals("concatenated operation");
                    final String sourceCode, targetCode;
                    final Integer methodCode;
                    if (isConversion) {
                        sourceCode = getOptionalString(result, 4);      // Optional for conversions, mandatory for all others.
                        targetCode = getOptionalString(result, 5);
                    } else {
                        sourceCode = getString(code, result, 4);
                        targetCode = getString(code, result, 5);
                    }
                    if (isConcatenated) {
                        methodCode = getOptionalInteger(result, 6);     // Not applicable to concatenated operation, mandatory for all others.
                    } else {
                        methodCode = getInteger(code, result, 6);
                    }
                    final String  version    = getOptionalString (result,  7);
                    final double  accuracy   = getOptionalDouble (result,  8);
                    final String  area       = getOptionalString (result,  9);
                    final String  scope      = getOptionalString (result, 10);
                    final String  remarks    = getOptionalString (result, 11);
                    final boolean deprecated = getOptionalBoolean(result, 12);
                    /*
                     * Create the source and target CRS for the codes fetched above.  Those CRS are optional only for
                     * conversions (the above calls to getString(code, result, …) verified that those CRS are defined
                     * for other kinds of operation). Conversions in EPSG database are usually "defining conversions"
                     * without source and target CRS.
                     *
                     * In EPSG database 6.7, all defining conversions are projections and their dimensions are always 2.
                     * However, this default number of dimensions is not generalizable to other kind of operation methods.
                     * For example, the "Geocentric translation" operation method has 3-dimensional source and target CRS.
                     */
                    final CoordinateReferenceSystem sourceCRS, targetCRS;
                    if (sourceCode != null) {
                        sourceCRS = owner.createCoordinateReferenceSystem(sourceCode);
                    } else {
                        sourceCRS = null;
                    }
                    if (targetCode != null) {
                        targetCRS = owner.createCoordinateReferenceSystem(targetCode);
                    } else {
                        targetCRS = null;
                    }
                    /*
                     * Get the operation method. This is mandatory for conversions and transformations
                     * (it was checked by getInteger(code, result, …) above in this method) but optional
                     * for concatenated operations. Fetching parameter values is part of this block.
                     */
                    final boolean       isDeferred = Semaphores.query(Semaphores.METADATA_ONLY);
                    ParameterValueGroup parameters = null;
                    OperationMethod     method     = null;
                    if (methodCode != null && !isDeferred) {
                        method = owner.createOperationMethod(methodCode.toString());
                        parameters = method.getParameters().createValue();
                        fillParameterValues(methodCode, epsg, parameters);
                    }
                    /*
                     * Creates common properties. The `version` and `accuracy` are usually defined
                     * for transformations only. However, we check them for all kind of operations
                     * (including conversions) and copy the information unconditionally if present.
                     *
                     * NOTE: This block must be executed last before object creations below, because
                     *       methods like createCoordinateReferenceSystem and createOperationMethod
                     *       overwrite the properties map.
                     */
                    Map<String,Object> opProperties = createProperties("Coordinate_Operation",
                            name, epsg, area, scope, remarks, deprecated);
                    opProperties.put(CoordinateOperation.OPERATION_VERSION_KEY, version);
                    if (!Double.isNaN(accuracy)) {
                        opProperties.put(CoordinateOperation.COORDINATE_OPERATION_ACCURACY_KEY,
                                PositionalAccuracyConstant.create(accuracy));
                    }
                    /*
                     * Creates the operation. Conversions should be the only operations allowed to have
                     * null source and target CRS. In such case, the operation is a defining conversion
                     * (usually to be used later as part of a ProjectedCRS creation).
                     */
                    final CoordinateOperation operation;
                    final CoordinateOperationFactory copFactory = owner.copFactory;
                    if (isDeferred) {
                        operation = new DeferredCoordinateOperation(opProperties, sourceCRS, targetCRS, owner);
                    } else if (isConversion && (sourceCRS == null || targetCRS == null)) {
                        operation = copFactory.createDefiningConversion(opProperties, method, parameters);
                    } else if (isConcatenated) {
                        /*
                         * Concatenated operation: we need to close the current result set, because
                         * we are going to invoke this method recursively in the following lines.
                         */
                        result.close();
                        opProperties = new HashMap<>(opProperties);         // Because this class uses a shared map.
                        final List<String> codes = new ArrayList<>();
                        try (ResultSet cr = executeQuery("Coordinate_Operation Path",
                                "SELECT SINGLE_OPERATION_CODE" +
                                 " FROM [Coordinate_Operation Path]" +
                                " WHERE (CONCAT_OPERATION_CODE = ?)" +
                                " ORDER BY OP_PATH_STEP", epsg))
                        {
                            while (cr.next()) {
                                codes.add(getString(code, cr, 1));
                            }
                        }
                        final CoordinateOperation[] operations = new CoordinateOperation[codes.size()];
                        ensureNoCycle(CoordinateOperation.class, epsg);
                        try {
                            for (int i=0; i<operations.length; i++) {
                                operations[i] = owner.createCoordinateOperation(codes.get(i));
                            }
                        } finally {
                            endOfRecursion(CoordinateOperation.class, epsg);
                        }
                        return copFactory.createConcatenatedOperation(opProperties, operations);
                    } else {
                        /*
                         * At this stage, the parameters are ready for use. Create the math transform and wrap it in the
                         * final operation (a Conversion or a Transformation). We need to give to MathTransformFactory
                         * some information about the context (source and target CRS) for allowing the factory to set
                         * the values of above-mentioned implicit parameters (semi-major and semi-minor axis lengths).
                         *
                         * The first special case may be removed in a future SIS version if the missing method is added
                         * to GeoAPI. Actually GeoAPI has a method doing part of the job, but incomplete (e.g. the pure
                         * GeoAPI method cannot handle Molodensky transform because it does not give the target datum).
                         */
                        opProperties = new HashMap<>(opProperties);             // Because this class uses a shared map.
                        final var builder = new ParameterizedTransformBuilder(owner.mtFactory, null);
                        builder.setParameters(parameters, true);
                        builder.setSourceAxes(sourceCRS);
                        builder.setTargetAxes(targetCRS);
                        final MathTransform mt = builder.create();
                        /*
                         * Give a hint to the factory about the type of the coordinate operation. ISO 19111 defines
                         * Conversion and Transformation, but SIS also have more specific sub-types.  We begin with
                         * what we can infer from the EPSG database.  Next, if the SIS MathTransform providers give
                         * more information, then we refine the type.
                         */
                        Class<? extends SingleOperation> opType;
                        if (isTransformation) {
                            opType = Transformation.class;
                        } else if (isConversion) {
                            opType = Conversion.class;
                        } else {
                            opType = SingleOperation.class;
                        }
                        final OperationMethod provider = builder.getMethod().orElse(null);
                        if (provider instanceof DefaultOperationMethod) {                 // SIS-specific
                            final Class<?> s = ((DefaultOperationMethod) provider).getOperationType();
                            if (s != null && opType.isAssignableFrom(s)) {
                                opType = s.asSubclass(SingleOperation.class);
                            }
                        }
                        opProperties.put(CoordinateOperations.OPERATION_TYPE_KEY, opType);
                        opProperties.put(CoordinateOperations.PARAMETERS_KEY, parameters);
                        /*
                         * Following restriction will be removed in a future SIS version if the method is added to GeoAPI.
                         */
                        if (!(copFactory instanceof DefaultCoordinateOperationFactory)) {
                            throw new UnsupportedOperationException(error().getString(
                                    Errors.Keys.UnsupportedImplementation_1, copFactory.getClass()));
                        }
                        operation = ((DefaultCoordinateOperationFactory) copFactory)
                                .createSingleOperation(opProperties, sourceCRS, targetCRS, null, method, mt);
                    }
                    returnValue = ensureSingleton(operation, returnValue, code);
                    if (result.isClosed()) {
                        return returnValue;
                    }
                }
            }
        } catch (SQLException exception) {
            throw databaseFailure(CoordinateOperation.class, code, exception);
        }
        if (returnValue == null) {
             throw noSuchAuthorityCode(CoordinateOperation.class, code);
        }
        return returnValue;
    }