org.n52.sos.ds.hibernate.HibernateFeatureQueryHandler Maven / Gradle / Ivy
/*
* Copyright (C) 2012-2020 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* License version 2 and the aforementioned licenses.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*/
package org.n52.sos.ds.hibernate;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.inject.Inject;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.spatial.criterion.SpatialProjections;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.n52.faroe.ConfigurationError;
import org.n52.faroe.Validation;
import org.n52.faroe.annotation.Configurable;
import org.n52.faroe.annotation.Setting;
import org.n52.iceland.cache.ContentCacheController;
import org.n52.iceland.exception.ows.concrete.NotYetSupportedException;
import org.n52.iceland.i18n.I18NDAORepository;
import org.n52.iceland.i18n.I18NSettings;
import org.n52.iceland.service.ServiceSettings;
import org.n52.janmayen.i18n.LocaleHelper;
import org.n52.series.db.beans.AbstractFeatureEntity;
import org.n52.series.db.beans.FeatureEntity;
import org.n52.shetland.ogc.filter.SpatialFilter;
import org.n52.shetland.ogc.gml.AbstractFeature;
import org.n52.shetland.ogc.gml.CodeWithAuthority;
import org.n52.shetland.ogc.om.features.samplingFeatures.AbstractSamplingFeature;
import org.n52.shetland.ogc.om.features.samplingFeatures.SamplingFeature;
import org.n52.shetland.ogc.ows.exception.NoApplicableCodeException;
import org.n52.shetland.ogc.ows.exception.OwsExceptionReport;
import org.n52.shetland.ogc.sos.SosConstants;
import org.n52.shetland.util.IdGenerator;
import org.n52.shetland.util.ReferencedEnvelope;
import org.n52.sos.cache.SosContentCache;
import org.n52.sos.ds.FeatureQueryHandler;
import org.n52.sos.ds.FeatureQueryHandlerQueryObject;
import org.n52.sos.ds.hibernate.create.FeatureVisitorContext;
import org.n52.sos.ds.hibernate.create.HibernateFeatureVisitor;
import org.n52.sos.ds.hibernate.create.HibernateGeometryVisitor;
import org.n52.sos.ds.hibernate.dao.DaoFactory;
import org.n52.sos.ds.hibernate.dao.HibernateSqlQueryConstants;
import org.n52.sos.ds.hibernate.util.HibernateConstants;
import org.n52.sos.ds.hibernate.util.HibernateHelper;
import org.n52.sos.ds.hibernate.util.QueryHelper;
import org.n52.sos.ds.hibernate.util.SpatialRestrictions;
import org.n52.sos.service.SosSettings;
import org.n52.sos.util.GeometryHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
@Configurable
public class HibernateFeatureQueryHandler
implements FeatureQueryHandler, HibernateSqlQueryConstants {
private static final Logger LOGGER = LoggerFactory.getLogger(HibernateFeatureQueryHandler.class);
private Locale defaultLocale;
private boolean showAllLanguages;
private I18NDAORepository i18NDAORepository;
private GeometryHandler geometryHandler;
private DaoFactory daoFactory;
private boolean updateFeatureGeometry;
private boolean createFeatureGeometryFromSamplingGeometries;
private ContentCacheController contentCacheController;
private String serviceURL;
@Inject
public void setDaoFactory(DaoFactory daoFactory) {
this.daoFactory = daoFactory;
}
@Inject
public void setI18NDAORepository(I18NDAORepository i18NDAORepository) {
this.i18NDAORepository = i18NDAORepository;
}
@Inject
public void setGeometryHandler(GeometryHandler geometryHandler) {
this.geometryHandler = geometryHandler;
}
@Inject
public void setContentCacheController(ContentCacheController ctrl) {
this.contentCacheController = ctrl;
}
@Setting(I18NSettings.I18N_DEFAULT_LANGUAGE)
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = LocaleHelper.decode(defaultLocale);
}
@Setting(I18NSettings.I18N_SHOW_ALL_LANGUAGE_VALUES)
public void setShowAllLanguages(boolean showAllLanguages) {
this.showAllLanguages = showAllLanguages;
}
@Setting(ServiceSettings.SERVICE_URL)
public void setServiceURL(final URI serviceURL) throws ConfigurationError {
Validation.notNull("Service URL", serviceURL);
String url = serviceURL.toString();
if (url.contains("?")) {
url = url.split("[?]")[0];
}
this.serviceURL = url;
}
@Override
public AbstractFeature getFeatureByID(FeatureQueryHandlerQueryObject queryObject) throws OwsExceptionReport {
AbstractFeatureEntity> feature = null;
if (queryObject.isSetFeatureObject() && queryObject.getFeatureObject() instanceof AbstractFeatureEntity) {
feature = (FeatureEntity) queryObject.getFeatureObject();
} else {
final Session session = HibernateSessionHolder.getSession(queryObject.getConnection());
try {
feature = daoFactory.getFeatureDAO().getFeature(queryObject.getFeatureIdentifier(), session);
} catch (final HibernateException he) {
throw new NoApplicableCodeException().causedBy(he).withMessage(
"An error occurred while querying feature data for a featureOfInterest identifier!");
}
}
return createSosAbstractFeature(feature, queryObject);
}
@SuppressWarnings("unchecked")
@Override
public Collection getFeatureIDs(FeatureQueryHandlerQueryObject queryObject) throws OwsExceptionReport {
final Session session = HibernateSessionHolder.getSession(queryObject.getConnection());
try {
if (getGeometryHandler().isSpatialDatasource()) {
final Criteria c
= session.createCriteria(AbstractFeatureEntity.class).setProjection(
Projections.distinct(Projections.property(AbstractFeatureEntity.IDENTIFIER)));
if (queryObject.isSetSpatialFilters()) {
SpatialFilter filter = queryObject.getSpatialFitler();
c.add(SpatialRestrictions.filter(FeatureEntity.GEOMETRY, filter.getOperator(),
getGeometryHandler().switchCoordinateAxisFromToDatasourceIfNeeded(filter.getGeometry())));
}
if (queryObject.isSetSpatialFilters()) {
c.add(Restrictions.in(FeatureEntity.IDENTIFIER, queryObject.getFeatures()));
}
return c.list();
} else {
Criteria c = session.createCriteria(FeatureEntity.class);
if (queryObject.isSetFeatures()) {
c.add(Restrictions.in(FeatureEntity.IDENTIFIER, queryObject.getFeatures()));
}
List identifiers = new LinkedList<>();
if (queryObject.isSetSpatialFilters()) {
SpatialFilter filter = queryObject.getSpatialFitler();
final List features = daoFactory.getFeatureDAO().getFeatures(session);
final Geometry envelope = getGeometryHandler().getFilterForNonSpatialDatasource(filter);
FeatureVisitorContext context = getDefaultContext()
.setSession(session)
.setRequestedLanguage(queryObject.getI18N());
for (final AbstractFeatureEntity feature : features) {
final Geometry geom = new HibernateGeometryVisitor(context).visit(feature);
if (geom != null && !geom.isEmpty() && envelope.contains(geom)) {
identifiers.add(feature.getIdentifier());
}
}
}
return identifiers;
}
} catch (final HibernateException he) {
throw new NoApplicableCodeException().causedBy(he)
.withMessage("An error occurred while querying feature identifiers for spatial filter!");
}
}
@Override
public Map getFeatures(FeatureQueryHandlerQueryObject queryObject)
throws OwsExceptionReport {
try {
if (getGeometryHandler().isSpatialDatasource()) {
return getFeaturesForSpatialDatasource(queryObject);
} else {
return getFeaturesForNonSpatialDatasource(queryObject);
}
} catch (final HibernateException he) {
throw new NoApplicableCodeException().causedBy(he)
.withMessage("Error while querying features from data source!");
}
}
@Override
public ReferencedEnvelope getEnvelopeForFeatureIDs(FeatureQueryHandlerQueryObject queryObject)
throws OwsExceptionReport {
final Session session = HibernateSessionHolder.getSession(queryObject.getConnection());
if (queryObject.isSetFeatures()) {
try {
// XXX workaround for Hibernate Spatial's lack of support for
// GeoDB's extent aggregate
// see
// http://www.hibernatespatial.org/pipermail/hibernatespatial-users/2013-August/000876.html
Dialect dialect = ((SessionFactoryImplementor) session.getSessionFactory()).getDialect();
if (getGeometryHandler().isSpatialDatasource()
&& HibernateHelper.supportsFunction(dialect, HibernateConstants.FUNC_EXTENT)) {
// Criteria featureExtentCriteria =
// session.createCriteria(FeatureEntity.class)
// .add(Restrictions.in(FeatureEntity.IDENTIFIER,
// featureIDs))
// .setProjection(SpatialProjections.extent(FeatureEntity.GEOMETRY));
// LOGGER.trace("QUERY getEnvelopeForFeatureIDs(featureIDs):
// {}",
// HibernateHelper.getSqlString(featureExtentCriteria));
// Geometry geom = (Geometry)
// featureExtentCriteria.uniqueResult();
Geometry geometry
= (Geometry) session
.createCriteria(AbstractFeatureEntity.class)
.add(QueryHelper.getCriterionForObjects(AbstractFeatureEntity.IDENTIFIER,
queryObject.getFeatures()))
.setProjection(SpatialProjections.extent(AbstractFeatureEntity.GEOMETRY))
.uniqueResult();
if (geometry != null) {
int srid = geometry.getSRID() > 0 ? geometry.getSRID() : getStorageEPSG();
geometry.setSRID(srid);
geometry = getGeometryHandler().switchCoordinateAxisFromToDatasourceIfNeeded(geometry);
return new ReferencedEnvelope(geometry.getEnvelopeInternal(), srid);
}
} else {
final Envelope envelope = new Envelope();
final List featuresOfInterest =
daoFactory.getFeatureDAO().getFeatureOfInterestObjects(queryObject.getFeatures(), session);
for (final AbstractFeatureEntity feature : featuresOfInterest) {
try {
// TODO Check if prepareGeometryForResponse required
// transform/switch
// final Geometry geom =
// getGeometryHandler().prepareGeometryForResponse(getGeomtery(feature),
// queryObject.getRequestedSrid());
FeatureVisitorContext context = getDefaultContext()
.setSession(session)
.setRequestedLanguage(queryObject.getI18N());
final Geometry geom = new HibernateGeometryVisitor(context).visit(feature);
if (geom != null && !geom.isEmpty()) {
envelope.expandToInclude(geom.getEnvelopeInternal());
}
} catch (final OwsExceptionReport owse) {
LOGGER.warn(String.format("Error while adding '%s' to envelope!",
feature.getId()), owse);
}
}
if (!envelope.isNull()) {
return new ReferencedEnvelope(envelope, getGeometryHandler().getStorageEPSG());
}
}
} catch (final HibernateException he) {
throw new NoApplicableCodeException().causedBy(he)
.withMessage("Exception thrown while requesting global feature envelope");
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.n52.sos.ds.FeatureQueryHandler#insertFeature(org.n52.sos.ogc.om.
* features .samplingFeatures.SamplingFeature, java.lang.Object)
*
* FIXME check semantics of this method in respect to its name and the
* documentation in the super class
*/
@Override
public String insertFeature(final AbstractSamplingFeature samplingFeature, final Object connection)
throws OwsExceptionReport {
if (!Strings.isNullOrEmpty(samplingFeature.getUrl())) {
if (samplingFeature.isSetIdentifier()) {
return samplingFeature.getIdentifierCodeWithAuthority().getValue();
} else {
return samplingFeature.getUrl();
}
} else {
final Session session = HibernateSessionHolder.getSession(connection);
String featureIdentifier;
if (!samplingFeature.isSetIdentifier()) {
featureIdentifier =
SosConstants.GENERATED_IDENTIFIER_PREFIX + IdGenerator.generate(samplingFeature.getXml());
samplingFeature.setIdentifier(new CodeWithAuthority(featureIdentifier));
}
return insertFeatureOfInterest(samplingFeature, session).getIdentifier();
}
}
@Override
public int getStorageEPSG() {
return getGeometryHandler().getStorageEPSG();
}
@Override
public int getStorage3DEPSG() {
return getGeometryHandler().getStorage3DEPSG();
}
private boolean isFeatureReferenced(final SamplingFeature samplingFeature) {
return !Strings.isNullOrEmpty(samplingFeature.getUrl());
}
/**
* Creates a map with FOI identifier and SOS feature
*
* @param features FeatureOfInterest objects
* @param queryObject SOS version
* @param session the session
* @return Map with FOI identifier and SOS feature
* @throws OwsExceptionReport * If feature type is not supported
*/
protected Map createSosFeatures(final List features,
final FeatureQueryHandlerQueryObject queryObject, Session session) throws OwsExceptionReport {
final Map sosAbstractFois = new HashMap<>(features.size());
for (final AbstractFeatureEntity feature : features) {
final AbstractFeature sosFeature = createSosAbstractFeature(feature, queryObject, session);
sosAbstractFois.put(feature.getIdentifier(), sosFeature);
}
// TODO if sampledFeatures are also in sosAbstractFois, reference them.
return sosAbstractFois;
}
protected FeatureEntity getFeatureOfInterest(final String identifier, final Geometry geometry,
final Session session) throws OwsExceptionReport {
if (!identifier.startsWith(SosConstants.GENERATED_IDENTIFIER_PREFIX)) {
return (FeatureEntity) session.createCriteria(FeatureEntity.class)
.add(Restrictions.eq(FeatureEntity.IDENTIFIER, identifier)).uniqueResult();
} else {
return (FeatureEntity) session.createCriteria(FeatureEntity.class)
.add(SpatialRestrictions.eq(FeatureEntity.GEOMETRY,
getGeometryHandler().switchCoordinateAxisFromToDatasourceIfNeeded(geometry)))
.uniqueResult();
}
}
protected AbstractFeature createSosAbstractFeature(final AbstractFeatureEntity feature,
final FeatureQueryHandlerQueryObject queryObject) throws OwsExceptionReport {
final Session session = HibernateSessionHolder.getSession(queryObject.getConnection());
return createSosAbstractFeature(feature, queryObject, session);
}
/**
* Creates a SOS feature from the FeatureOfInterest object
*
* @param feature FeatureOfInterest object
* @param queryObject Query object
* @param session the session
* @return SOS feature An SOS feature
* @throws OwsExceptionReport If an error occurs
*/
protected AbstractFeature createSosAbstractFeature(final AbstractFeatureEntity feature,
final FeatureQueryHandlerQueryObject queryObject, Session session) throws OwsExceptionReport {
if (feature == null) {
return null;
}
FeatureVisitorContext context = getDefaultContext()
.setSession(session)
.setRequestedLanguage(queryObject.getI18N());
return new HibernateFeatureVisitor(context).visit(feature);
}
private FeatureVisitorContext getDefaultContext() {
return new FeatureVisitorContext()
.setStorageEPSG(getStorageEPSG())
.setStorage3DEPSG(getStorage3DEPSG())
.setGeometryHandler(geometryHandler)
.setDaoFactory(daoFactory)
.setShowAllLanguages(showAllLanguages)
.setDefaultLanguage(defaultLocale)
.setUpdateFeatureGeometry(updateFeatureGeometry)
.setCreateFeatureGeometryFromSamplingGeometries(createFeatureGeometryFromSamplingGeometries)
.setI18NDAORepository(i18NDAORepository)
.setCache((SosContentCache) contentCacheController.getCache())
.setServiceURL(serviceURL);
}
protected AbstractFeatureEntity insertFeatureOfInterest(AbstractSamplingFeature samplingFeature,
Session session) throws OwsExceptionReport {
if (!getGeometryHandler().isSpatialDatasource()) {
throw new NotYetSupportedException("Insertion of full encoded features for non spatial datasources");
}
return daoFactory.getFeatureDAO().insertFeature(samplingFeature, session);
}
protected Map getFeaturesForNonSpatialDatasource(
FeatureQueryHandlerQueryObject queryObject) throws OwsExceptionReport {
final Session session = HibernateSessionHolder.getSession(queryObject.getConnection());
final Map featureMap = new HashMap<>(0);
List envelopes = null;
boolean hasSpatialFilter = false;
if (queryObject.isSetSpatialFilters()) {
hasSpatialFilter = true;
envelopes = new ArrayList<>(queryObject.getSpatialFilters().size());
for (final SpatialFilter filter : queryObject.getSpatialFilters()) {
envelopes.add(getGeometryHandler().getFilterForNonSpatialDatasource(filter));
}
}
final List featuresOfInterest =
daoFactory.getFeatureDAO().getFeatureOfInterestObjects(queryObject.getFeatures(), session);
for (final AbstractFeatureEntity feature : featuresOfInterest) {
final AbstractSamplingFeature sosAbstractFeature =
(AbstractSamplingFeature) createSosAbstractFeature(feature, queryObject, session);
if (!hasSpatialFilter) {
featureMap.put(sosAbstractFeature.getIdentifierCodeWithAuthority().getValue(), sosAbstractFeature);
} else if (getGeometryHandler().featureIsInFilter(sosAbstractFeature.getGeometry(), envelopes)) {
featureMap.put(sosAbstractFeature.getIdentifierCodeWithAuthority().getValue(), sosAbstractFeature);
}
}
return featureMap;
}
protected Map getFeaturesForSpatialDatasource(FeatureQueryHandlerQueryObject queryObject)
throws OwsExceptionReport {
final Session session = HibernateSessionHolder.getSession(queryObject.getConnection());
final Criteria c =
session.createCriteria(FeatureEntity.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
boolean filtered = false;
if (queryObject.isSetFeatures()) {
c.add(QueryHelper.getCriterionForObjects(FeatureEntity.IDENTIFIER, queryObject.getFeatures()));
filtered = true;
}
if (queryObject.isSetSpatialFilters()) {
for (final SpatialFilter filter : queryObject.getSpatialFilters()) {
filter.setGeometry(getGeometryHandler()
.switchCoordinateAxisFromToDatasourceIfNeeded(filter.getGeometry().toGeometry()));
}
}
List features = daoFactory.getFeatureDAO().getFeatures(queryObject.getFeatures(),
queryObject.getSpatialFilters(), session);
if (features != null) {
return createSosFeatures(features, queryObject, session);
} else {
return Collections.emptyMap();
}
}
protected GeometryHandler getGeometryHandler() {
return geometryHandler;
}
@Setting(SosSettings.CREATE_FOI_GEOM_FROM_SAMPLING_GEOMS)
public void setCreateFeatureGeometryFromSamplingGeometries(boolean createFeatureGeometryFromSamplingGeometries) {
this.createFeatureGeometryFromSamplingGeometries = createFeatureGeometryFromSamplingGeometries;
}
@Setting(SosSettings.UPDATE_FEATURE_GEOMETRY)
public void setUpdateFeatureGeometry(boolean updateFeatureGeometry) {
this.updateFeatureGeometry = updateFeatureGeometry;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy