blob: c7f892ba621171d41d9f41384c27669d467cc80f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sis.filter.sqlmm;
import java.util.List;
import java.nio.ByteBuffer;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.geometry.wrapper.Geometries;
import org.apache.sis.geometry.wrapper.GeometryWrapper;
import org.apache.sis.util.Classes;
import org.apache.sis.util.resources.Errors;
// Specific to the geoapi-3.1 and geoapi-4.0 branches:
import org.opengis.filter.Expression;
import org.opengis.filter.InvalidFilterValueException;
/**
* SQLMM spatial functions taking non-geometry operands and creating a geometry.
* Geometries can be created from Well-Known Text (WKT), Well-Known Binary (WKB)
* Geographic Markup Language (GML), or a list of points or coordinates.
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
*
* @param <R> the type of resources (e.g. {@link org.opengis.feature.Feature}) used as inputs.
* @param <G> the implementation type of geometry objects.
*/
class GeometryConstructor<R,G> extends FunctionWithSRID<R> {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = -4644842662358995787L;
/**
* The expression giving the geometry.
*/
@SuppressWarnings("serial") // Most SIS implementations are serializable.
final Expression<R,?> geometry;
/**
* The library to use for creating geometry objects.
*/
final Geometries<G> library;
/**
* Creates a new function for the given parameters.
*/
GeometryConstructor(final SQLMM operation, final Expression<R,?>[] parameters, final Geometries<G> library) {
super(operation, parameters, parameters.length >= operation.maxParamCount ? PRESENT : ABSENT);
this.geometry = parameters[0];
this.library = library;
}
/**
* Creates a new expression of the same type as this expression, but with an optimized geometry.
* The optimization may be a geometry computed immediately if all operator parameters are literals.
*/
@Override
public Expression<R,Object> recreate(final Expression<R,?>[] effective) {
return new GeometryConstructor<>(operation, effective, getGeometryLibrary());
}
/**
* Returns the class of resources expected by this expression.
*/
@Override
public Class<? super R> getResourceClass() {
return specializedClass(geometry.getResourceClass(), super.getResourceClass());
}
/**
* Returns the sub-expressions that will be evaluated to provide the parameters to the function.
*/
@Override
public final List<Expression<R,?>> getParameters() {
return (srid != null) ? List.of(geometry, srid) : List.of(geometry);
}
/**
* Returns a handler for the library of geometric objects used by this expression.
*/
@Override
final Geometries<?> getGeometryLibrary() {
return library;
}
/**
* Creates a geometry from the content of the given object.
*
* @param input the object to be evaluated by the expression.
* @return geometry created by the expression, or {@code null} if the operation failed..
*/
@Override
public Object apply(final R input) {
final Object value = geometry.apply(input);
try {
final GeometryWrapper result;
if (value == null) {
return null;
} else if (value instanceof byte[]) {
result = library.parseWKB(ByteBuffer.wrap((byte[]) value));
} else if (value instanceof ByteBuffer) {
result = library.parseWKB((ByteBuffer) value);
} else if (value instanceof String) {
result = library.parseWKT((String) value);
} else {
result = library.createFromComponents(operation.getGeometryType().get(), value);
}
final Object geometry = library.getGeometry(result);
final Class<?> expected = operation.getReturnType(library);
if (!expected.isInstance(geometry)) {
throw new InvalidFilterValueException(Errors.format(
Errors.Keys.IllegalArgumentClass_3, "geom", expected, Classes.getClass(geometry)));
}
if (srid != null) {
final CoordinateReferenceSystem crs = getTargetCRS(input);
if (crs != null) {
result.setCoordinateReferenceSystem(crs);
}
}
return geometry;
} catch (Exception e) {
warning(e, false);
}
return null;
}
}