/**
* Copyright (C) 2012-2017 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.dao;
import static org.hibernate.criterion.Restrictions.eq;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
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.n52.sos.ds.hibernate.entities.AbstractObservation;
import org.n52.sos.ds.hibernate.entities.AbstractObservationTime;
import org.n52.sos.ds.hibernate.entities.BlobObservation;
import org.n52.sos.ds.hibernate.entities.BooleanObservation;
import org.n52.sos.ds.hibernate.entities.CategoryObservation;
import org.n52.sos.ds.hibernate.entities.CountObservation;
import org.n52.sos.ds.hibernate.entities.FeatureOfInterest;
import org.n52.sos.ds.hibernate.entities.NumericObservation;
import org.n52.sos.ds.hibernate.entities.ObservableProperty;
import org.n52.sos.ds.hibernate.entities.Observation;
import org.n52.sos.ds.hibernate.entities.ObservationConstellation;
import org.n52.sos.ds.hibernate.entities.ObservationInfo;
import org.n52.sos.ds.hibernate.entities.Offering;
import org.n52.sos.ds.hibernate.entities.Procedure;
import org.n52.sos.ds.hibernate.entities.SweDataArrayObservation;
import org.n52.sos.ds.hibernate.entities.TextObservation;
import org.n52.sos.ds.hibernate.util.HibernateConstants;
import org.n52.sos.ds.hibernate.util.HibernateGeometryCreator;
import org.n52.sos.ds.hibernate.util.HibernateHelper;
import org.n52.sos.ds.hibernate.util.ScrollableIterable;
import org.n52.sos.ogc.ows.OwsExceptionReport;
import org.n52.sos.ogc.sos.SosConstants.SosIndeterminateTime;
import org.n52.sos.request.GetObservationRequest;
import org.n52.sos.util.CollectionHelper;
import org.n52.sos.util.GeometryHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
/**
* Hibernate data access class for observation
*
* @author CarstenHollmann
* @since 4.0.0
*/
public class ObservationDAO extends AbstractObservationDAO {
private static final Logger LOGGER = LoggerFactory.getLogger(ObservationDAO.class);
public static final String SQL_QUERY_GET_LATEST_OBSERVATION_TIME = "getLatestObservationTime";
public static final String SQL_QUERY_GET_FIRST_OBSERVATION_TIME = "getFirstObservationTime";
@Override
protected void addObservationIdentifiersToObservation(ObservationIdentifiers observationIdentifiers,
AbstractObservation observation, Session session) {
Observation hObservation = (Observation) observation;
hObservation.setFeatureOfInterest(observationIdentifiers.getFeatureOfInterest());
hObservation.setObservableProperty(observationIdentifiers.getObservableProperty());
hObservation.setProcedure(observationIdentifiers.getProcedure());
}
@Override
public Criteria getObservationInfoCriteriaForFeatureOfInterestAndProcedure(String feature, String procedure,
Session session) {
Criteria criteria = getDefaultObservationInfoCriteria(session);
criteria.createCriteria(AbstractObservation.FEATURE_OF_INTEREST)
.add(eq(FeatureOfInterest.IDENTIFIER, feature));
criteria.createCriteria(AbstractObservation.PROCEDURE).add(eq(Procedure.IDENTIFIER, procedure));
return criteria;
}
@Override
public Criteria getObservationInfoCriteriaForFeatureOfInterestAndOffering(String feature, String offering,
Session session) {
Criteria criteria = getDefaultObservationInfoCriteria(session);
criteria.createCriteria(AbstractObservation.FEATURE_OF_INTEREST)
.add(eq(FeatureOfInterest.IDENTIFIER, feature));
criteria.createCriteria(AbstractObservation.OFFERINGS).add(eq(Offering.IDENTIFIER, offering));
return criteria;
}
/**
* Update observation by setting deleted flag
*
* @param procedure
* Procedure for which the observations should be updated
* @param deleteFlag
* New deleted flag value
* @param session
* Hibernate Session
*/
public void updateObservationSetAsDeletedForProcedure(String procedure, boolean deleteFlag, Session session) {
Criteria criteria = getDefaultObservationInfoCriteria(session);
criteria.createCriteria(AbstractObservation.PROCEDURE).add(Restrictions.eq(Procedure.IDENTIFIER, procedure));
ScrollableIterable<AbstractObservation> scroll = ScrollableIterable.fromCriteria(criteria);
updateObservation(scroll, deleteFlag, session);
}
/**
* Add observableProperty restriction to Hibernate Criteria for Observation
*
* @param criteria
* Hibernate Criteria for Observation
* @param observableProperty
* ObservableProperty identifier to add
*/
public void addObservablePropertyRestrictionToObservationCriteria(Criteria criteria, String observableProperty) {
criteria.createCriteria(AbstractObservation.OBSERVABLE_PROPERTY).add(
Restrictions.eq(ObservableProperty.IDENTIFIER, observableProperty));
}
/**
* Add procedure restriction to Hibernate Criteria for Observation
*
* @param criteria
* Hibernate Criteria for Observation
* @param procedure
* Procedure identifier to add
*/
public void addProcedureRestrictionToObservationCriteria(Criteria criteria, String procedure) {
criteria.createCriteria(AbstractObservation.PROCEDURE).add(Restrictions.eq(Procedure.IDENTIFIER, procedure));
}
/**
* Add featureOfInterest restriction to Hibernate Criteria for Observation
*
* @param criteria
* Hibernate Criteria for Observation
* @param featureOfInterest
* FeatureOfInterest identifier to add
*/
public void addFeatureOfInterestRestrictionToObservationCriteria(Criteria criteria, String featureOfInterest) {
criteria.createCriteria(AbstractObservation.FEATURE_OF_INTEREST).add(
eq(FeatureOfInterest.IDENTIFIER, featureOfInterest));
}
@Override
public Criteria getObservationCriteriaForProcedure(String procedure, Session session) {
Criteria criteria = getDefaultObservationCriteria(session);
addProcedureRestrictionToObservationCriteria(criteria, procedure);
return criteria;
}
@Override
public Criteria getObservationCriteriaForObservableProperty(String observableProperty, Session session) {
Criteria criteria = getDefaultObservationCriteria(session);
addObservablePropertyRestrictionToObservationCriteria(criteria, observableProperty);
return criteria;
}
@Override
public Criteria getObservationCriteriaForFeatureOfInterest(String featureOfInterest, Session session) {
Criteria criteria = getDefaultObservationCriteria(session);
addFeatureOfInterestRestrictionToObservationCriteria(criteria, featureOfInterest);
return criteria;
}
@Override
public Criteria getObservationCriteriaFor(String procedure, String observableProperty, Session session) {
Criteria criteria = getDefaultObservationCriteria(session);
addProcedureRestrictionToObservationCriteria(criteria, procedure);
addObservablePropertyRestrictionToObservationCriteria(criteria, observableProperty);
return criteria;
}
@Override
public Criteria getObservationCriteriaFor(String procedure, String observableProperty, String featureOfInterest,
Session session) {
Criteria criteria = getDefaultObservationCriteria(session);
addProcedureRestrictionToObservationCriteria(criteria, procedure);
addObservablePropertyRestrictionToObservationCriteria(criteria, observableProperty);
addFeatureOfInterestRestrictionToObservationCriteria(criteria, featureOfInterest);
return criteria;
}
@SuppressWarnings("unchecked")
public Collection<String> getObservationIdentifiers(String procedureIdentifier, Session session) {
Criteria criteria =
session.createCriteria(ObservationInfo.class)
.setProjection(Projections.distinct(Projections.property(ObservationInfo.IDENTIFIER)))
.add(Restrictions.isNotNull(ObservationInfo.IDENTIFIER))
.add(Restrictions.eq(ObservationInfo.DELETED, false));
criteria.createCriteria(ObservationInfo.PROCEDURE).add(
Restrictions.eq(Procedure.IDENTIFIER, procedureIdentifier));
LOGGER.debug("QUERY ObservationDAO.getObservationIdentifiers(procedureIdentifier): {}",
HibernateHelper.getSqlString(criteria));
return criteria.list();
}
@SuppressWarnings("unchecked")
private List<AbstractObservation> getObservationsFor(GetObservationRequest request, Collection<String> features,
Criterion filterCriterion, SosIndeterminateTime sosIndeterminateTime, Session session)
throws OwsExceptionReport {
// final Criteria c = getDefaultObservationCriteria(Observation.class,
// session);
//
// checkAndAddSpatialFilteringProfileCriterion(c, request, session);
//
// if (CollectionHelper.isNotEmpty(request.getProcedures())) {
// c.createCriteria(
// Observation.PROCEDURE).add(Restrictions.in(Procedure.IDENTIFIER,
// request.getProcedures()));
// }
//
// if (CollectionHelper.isNotEmpty(request.getObservedProperties())) {
// c.createCriteria(Observation.OBSERVABLE_PROPERTY).add(Restrictions.in(ObservableProperty.IDENTIFIER,
// request.getObservedProperties()));
// }
//
// if (CollectionHelper.isNotEmpty(features)) {
// c.createCriteria(Observation.FEATURE_OF_INTEREST).add(Restrictions.in(FeatureOfInterest.IDENTIFIER,
// features));
// }
//
// if (CollectionHelper.isNotEmpty(request.getOfferings())) {
// c.createCriteria(Observation.OFFERINGS).add(Restrictions.in(Offering.IDENTIFIER,
// request.getOfferings()));
// }
//
// String logArgs = "request, features, offerings";
// if (filterCriterion != null) {
// logArgs += ", filterCriterion";
// c.add(filterCriterion);
// }
// if (sosIndeterminateTime != null) {
// logArgs += ", sosIndeterminateTime";
// addIndeterminateTimeRestriction(c, sosIndeterminateTime);
// }
// LOGGER.debug("QUERY getSeriesObservationFor({}): {}", logArgs,
// HibernateHelper.getSqlString(c));
return getObservationCriteriaFor(request, features, filterCriterion, sosIndeterminateTime, session).list();
}
protected Criteria getObservationCriteriaFor(GetObservationRequest request, Collection<String> features,
Criterion filterCriterion, SosIndeterminateTime sosIndeterminateTime, Session session)
throws OwsExceptionReport {
final Criteria c = getDefaultObservationCriteria(session);
checkAndAddSpatialFilteringProfileCriterion(c, request, session);
if (CollectionHelper.isNotEmpty(request.getProcedures())) {
c.createCriteria(Observation.PROCEDURE)
.add(Restrictions.in(Procedure.IDENTIFIER, request.getProcedures()));
}
if (CollectionHelper.isNotEmpty(request.getObservedProperties())) {
c.createCriteria(Observation.OBSERVABLE_PROPERTY).add(
Restrictions.in(ObservableProperty.IDENTIFIER, request.getObservedProperties()));
}
if (CollectionHelper.isNotEmpty(features)) {
c.createCriteria(Observation.FEATURE_OF_INTEREST).add(
Restrictions.in(FeatureOfInterest.IDENTIFIER, features));
}
if (CollectionHelper.isNotEmpty(request.getOfferings())) {
c.createCriteria(Observation.OFFERINGS).add(Restrictions.in(Offering.IDENTIFIER, request.getOfferings()));
}
String logArgs = "request, features, offerings";
if (filterCriterion != null) {
logArgs += ", filterCriterion";
c.add(filterCriterion);
}
if (sosIndeterminateTime != null) {
logArgs += ", sosIndeterminateTime";
addIndeterminateTimeRestriction(c, sosIndeterminateTime);
}
LOGGER.debug("QUERY getSeriesObservationFor({}): {}", logArgs, HibernateHelper.getSqlString(c));
return c;
}
public Collection<AbstractObservation> getObservationsFor(GetObservationRequest request, Set<String> features,
Criterion filterCriterion, Session session) throws OwsExceptionReport {
return getObservationsFor(request, features, filterCriterion, null, session);
}
public Collection<AbstractObservation> getObservationsFor(GetObservationRequest request, Set<String> features,
SosIndeterminateTime sosIndeterminateTime, Session session) throws OwsExceptionReport {
return getObservationsFor(request, features, null, sosIndeterminateTime, session);
}
public Collection<AbstractObservation> getObservationsFor(GetObservationRequest request, Set<String> features,
Session session) throws OwsExceptionReport {
return getObservationsFor(request, features, null, null, session);
}
@SuppressWarnings("unchecked")
public Collection<? extends AbstractObservation> getObservationsFor(ObservationConstellation oc,
HashSet<String> features, GetObservationRequest request, SosIndeterminateTime sosIndeterminateTime,
Session session) throws OwsExceptionReport {
final Criteria c = getDefaultObservationCriteria(session);
checkAndAddSpatialFilteringProfileCriterion(c, request, session);
c.createCriteria(Observation.PROCEDURE).add(Restrictions.eq(Procedure.ID, oc.getProcedure().getProcedureId()));
c.createCriteria(Observation.OBSERVABLE_PROPERTY).add(
Restrictions.eq(ObservableProperty.ID, oc.getObservableProperty().getObservablePropertyId()));
if (CollectionHelper.isNotEmpty(features)) {
c.createCriteria(Observation.FEATURE_OF_INTEREST).add(
Restrictions.in(FeatureOfInterest.IDENTIFIER, features));
}
c.createCriteria(Observation.OFFERINGS).add(Restrictions.eq(Offering.ID, oc.getOffering().getOfferingId()));
String logArgs = "request, features, offerings";
logArgs += ", sosIndeterminateTime";
addIndeterminateTimeRestriction(c, sosIndeterminateTime);
LOGGER.debug("QUERY getSeriesObservationFor({}): {}", logArgs, HibernateHelper.getSqlString(c));
return c.list();
}
public ScrollableResults getStreamingObservationsFor(GetObservationRequest request, Set<String> features,
Criterion temporalFilterCriterion, Session session) throws HibernateException, OwsExceptionReport {
return getObservationCriteriaFor(request, features, temporalFilterCriterion, null, session).setReadOnly(true)
.scroll(ScrollMode.FORWARD_ONLY);
}
public ScrollableResults getStreamingObservationsFor(GetObservationRequest request, Set<String> features,
Session session) throws HibernateException, OwsExceptionReport {
return getObservationCriteriaFor(request, features, null, null, session).setReadOnly(true).scroll(
ScrollMode.FORWARD_ONLY);
}
public ScrollableResults getNotMatchingSeries(Set<Long> procedureIds, Set<Long> observablePropertyIds,
Set<Long> featureIds, GetObservationRequest request, Set<String> features,
Criterion temporalFilterCriterion, Session session) throws OwsExceptionReport {
Criteria c =
getObservationCriteriaFor(request, features, temporalFilterCriterion, null, session);
addAliasAndNotRestrictionFor(c, procedureIds, observablePropertyIds, featureIds);
return c.setReadOnly(true).scroll(ScrollMode.FORWARD_ONLY);
}
public ScrollableResults getNotMatchingSeries(Set<Long> procedureIds, Set<Long> observablePropertyIds,
Set<Long> featureIds, GetObservationRequest request, Set<String> features, Session session) throws OwsExceptionReport {
Criteria c = getObservationCriteriaFor(request, features, null, null, session);
addAliasAndNotRestrictionFor(c, procedureIds, observablePropertyIds, featureIds);
return c.setReadOnly(true).scroll(ScrollMode.FORWARD_ONLY);
}
@SuppressWarnings("unchecked")
@Override
public List<Geometry> getSamplingGeometries(String feature, Session session) throws OwsExceptionReport {
Criteria criteria = getDefaultObservationInfoCriteria(session);
criteria.createCriteria(AbstractObservation.FEATURE_OF_INTEREST).add(eq(FeatureOfInterest.IDENTIFIER, feature));
criteria.addOrder(Order.asc(AbstractObservationTime.PHENOMENON_TIME_START));
if (HibernateHelper.isColumnSupported(getObservationInfoClass(), AbstractObservationTime.SAMPLING_GEOMETRY)) {
criteria.add(Restrictions.isNotNull(AbstractObservationTime.SAMPLING_GEOMETRY));
criteria.setProjection(Projections.property(AbstractObservationTime.SAMPLING_GEOMETRY));
LOGGER.debug("QUERY getSamplingGeometries(feature): {}", HibernateHelper.getSqlString(criteria));
return criteria.list();
} else if (HibernateHelper.isColumnSupported(getObservationInfoClass(), AbstractObservationTime.LONGITUDE)
&& HibernateHelper.isColumnSupported(getObservationInfoClass(), AbstractObservationTime.LATITUDE)) {
criteria.add(Restrictions.and(Restrictions.isNotNull(AbstractObservationTime.LATITUDE),
Restrictions.isNotNull(AbstractObservationTime.LONGITUDE)));
List<Geometry> samplingGeometries = Lists.newArrayList();
LOGGER.debug("QUERY getSamplingGeometries(feature): {}", HibernateHelper.getSqlString(criteria));
for (AbstractObservationTime element : (List<AbstractObservationTime>)criteria.list()) {
samplingGeometries.add(new HibernateGeometryCreator().createGeometry(element));
}
return samplingGeometries;
}
return Collections.emptyList();
}
@Override
public Long getSamplingGeometriesCount(String feature, Session session) throws OwsExceptionReport {
Criteria criteria = getDefaultObservationInfoCriteria(session);
criteria.createCriteria(AbstractObservation.FEATURE_OF_INTEREST).add(eq(FeatureOfInterest.IDENTIFIER, feature));
criteria.setProjection(Projections.count(AbstractObservationTime.ID));
if (GeometryHandler.getInstance().isSpatialDatasource()) {
criteria.add(Restrictions.isNotNull(AbstractObservationTime.SAMPLING_GEOMETRY));
LOGGER.debug("QUERY getSamplingGeometriesCount(feature): {}", HibernateHelper.getSqlString(criteria));
return (Long)criteria.uniqueResult();
} else {
criteria.add(Restrictions.and(Restrictions.isNotNull(AbstractObservationTime.LATITUDE),
Restrictions.isNotNull(AbstractObservationTime.LONGITUDE)));
LOGGER.debug("QUERY getSamplingGeometriesCount(feature): {}", HibernateHelper.getSqlString(criteria));
return (Long)criteria.uniqueResult();
}
}
@SuppressWarnings("unchecked")
@Override
public Envelope getBboxFromSamplingGeometries(String feature, Session session) throws OwsExceptionReport {
Criteria criteria = getDefaultObservationInfoCriteria(session);
criteria.createCriteria(AbstractObservation.FEATURE_OF_INTEREST).add(eq(FeatureOfInterest.IDENTIFIER, feature));
if (GeometryHandler.getInstance().isSpatialDatasource()) {
criteria.add(Restrictions.isNotNull(AbstractObservationTime.SAMPLING_GEOMETRY));
Dialect dialect = ((SessionFactoryImplementor) session.getSessionFactory()).getDialect();
if (HibernateHelper.supportsFunction(dialect, HibernateConstants.FUNC_EXTENT)) {
criteria.setProjection(SpatialProjections.extent(AbstractObservationTime.SAMPLING_GEOMETRY));
LOGGER.debug("QUERY getBboxFromSamplingGeometries(feature): {}",
HibernateHelper.getSqlString(criteria));
return (Envelope) criteria.uniqueResult();
}
} else if (HibernateHelper.isColumnSupported(getObservationTimeClass(), AbstractObservationTime.SAMPLING_GEOMETRY)) {
criteria.add(Restrictions.isNotNull(AbstractObservationTime.SAMPLING_GEOMETRY));
criteria.setProjection(Projections.property(AbstractObservationTime.SAMPLING_GEOMETRY));
LOGGER.debug("QUERY getBboxFromSamplingGeometries(feature): {}",
HibernateHelper.getSqlString(criteria));
Envelope envelope = new Envelope();
for (Geometry geom : (List<Geometry>) criteria.list()) {
envelope.expandToInclude(geom.getEnvelopeInternal());
}
return envelope;
} else if (HibernateHelper.isColumnSupported(getObservationTimeClass(), AbstractObservationTime.LATITUDE) && HibernateHelper.isColumnSupported(getObservationTimeClass(), AbstractObservationTime.LONGITUDE)) {
criteria.add(Restrictions.and(Restrictions.isNotNull(AbstractObservationTime.LATITUDE),
Restrictions.isNotNull(AbstractObservationTime.LONGITUDE)));
criteria.setProjection(Projections.projectionList()
.add(Projections.min(AbstractObservationTime.LATITUDE))
.add(Projections.min(AbstractObservation.LONGITUDE))
.add(Projections.max(AbstractObservationTime.LATITUDE))
.add(Projections.max(AbstractObservation.LONGITUDE)));
LOGGER.debug("QUERY getBboxFromSamplingGeometries(feature): {}", HibernateHelper.getSqlString(criteria));
MinMaxLatLon minMaxLatLon = new MinMaxLatLon((Object[]) criteria.uniqueResult());
Envelope envelope = new Envelope(minMaxLatLon.getMinLon(), minMaxLatLon.getMaxLon(),
minMaxLatLon.getMinLat(), minMaxLatLon.getMaxLat());
return envelope;
}
return null;
}
private void addAliasAndNotRestrictionFor(Criteria c, Set<Long> procedureIds, Set<Long> observablePropertyIds, Set<Long> featureIds) {
c.createAlias(Observation.PROCEDURE, "p").createAlias(Observation.OBSERVABLE_PROPERTY, "op")
.createAlias(Observation.FEATURE_OF_INTEREST, "f");
c.add(Restrictions.not(Restrictions.in("p." + Procedure.ID, procedureIds)));
c.add(Restrictions.not(Restrictions.in("op." + ObservableProperty.ID, observablePropertyIds)));
c.add(Restrictions.not(Restrictions.in("f." + FeatureOfInterest.ID, featureIds)));
}
@Override
protected Class<?> getObservationClass() {
return Observation.class;
}
@Override
protected Class<?> getObservationInfoClass() {
return ObservationInfo.class;
}
@Override
protected Class<?> getObservationTimeClass() {
return ObservationInfo.class;
}
@Override
protected Class<?> getBlobObservationClass() {
return BlobObservation.class;
}
@Override
protected Class<?> getBooleanObservationClass() {
return BooleanObservation.class;
}
@Override
protected Class<?> getCategoryObservationClass() {
return CategoryObservation.class;
}
@Override
protected Class<?> getCountObservationClass() {
return CountObservation.class;
}
@Override
protected Class<?> getGeometryObservationClass() {
return null;
}
@Override
protected Class<?> getNumericObservationClass() {
return NumericObservation.class;
}
@Override
protected Class<?> getSweDataArrayObservationClass() {
return SweDataArrayObservation.class;
}
@Override
protected Class<?> getTextObservationClass() {
return TextObservation.class;
}
}