/**
* 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.util.procedure.generator;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.n52.sos.cache.ContentCache;
import org.n52.sos.ds.I18NDAO;
import org.n52.sos.ds.hibernate.dao.AbstractObservationDAO;
import org.n52.sos.ds.hibernate.dao.DaoFactory;
import org.n52.sos.ds.hibernate.dao.ObservationConstellationDAO;
import org.n52.sos.ds.hibernate.entities.AbstractObservation;
import org.n52.sos.ds.hibernate.entities.EntitiyHelper;
import org.n52.sos.ds.hibernate.entities.ObservationConstellation;
import org.n52.sos.ds.hibernate.entities.Procedure;
import org.n52.sos.ds.hibernate.entities.interfaces.BlobObservation;
import org.n52.sos.ds.hibernate.entities.interfaces.BooleanObservation;
import org.n52.sos.ds.hibernate.entities.interfaces.CategoryObservation;
import org.n52.sos.ds.hibernate.entities.interfaces.CountObservation;
import org.n52.sos.ds.hibernate.entities.interfaces.GeometryObservation;
import org.n52.sos.ds.hibernate.entities.interfaces.NumericObservation;
import org.n52.sos.ds.hibernate.entities.interfaces.TextObservation;
import org.n52.sos.ds.hibernate.entities.series.Series;
import org.n52.sos.ds.hibernate.util.HibernateHelper;
import org.n52.sos.exception.CodedException;
import org.n52.sos.exception.ows.NoApplicableCodeException;
import org.n52.sos.ogc.OGCConstants;
import org.n52.sos.ogc.om.OmConstants;
import org.n52.sos.ogc.ows.OwsExceptionReport;
import org.n52.sos.ogc.sensorML.AbstractProcess;
import org.n52.sos.ogc.sensorML.elements.SmlIdentifier;
import org.n52.sos.ogc.sensorML.elements.SmlIo;
import org.n52.sos.ogc.sensorML.elements.SmlPosition;
import org.n52.sos.ogc.swe.SweAbstractDataComponent;
import org.n52.sos.ogc.swe.SweConstants;
import org.n52.sos.ogc.swe.SweConstants.SweCoordinateName;
import org.n52.sos.ogc.swe.SweCoordinate;
import org.n52.sos.ogc.swe.simpleType.SweBoolean;
import org.n52.sos.ogc.swe.simpleType.SweCategory;
import org.n52.sos.ogc.swe.simpleType.SweCount;
import org.n52.sos.ogc.swe.simpleType.SweQuantity;
import org.n52.sos.ogc.swe.simpleType.SweText;
import org.n52.sos.service.Configurator;
import org.n52.sos.util.CollectionHelper;
import org.n52.sos.util.GeometryHandler;
import org.n52.sos.util.JavaHelper;
import org.n52.sos.util.StringHelper;
import org.n52.sos.util.http.HTTPStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Abstract generator class for SensorML procedure descriptions
*
* @author Carsten Hollmann <c.hollmann@52north.org>
* @since 4.2.0
*
*/
public abstract class AbstractHibernateProcedureDescriptionGeneratorSml extends
AbstractHibernateProcedureDescriptionGenerator {
private static final Logger LOGGER = LoggerFactory
.getLogger(AbstractHibernateProcedureDescriptionGeneratorSml.class);
public static final String SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY = "getUnitForObservableProperty";
public static final String SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE =
"getUnitForObservablePropertyProcedure";
public static final String SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE_OFFERING =
"getUnitForObservablePropertyProcedureOffering";
protected static final String POSITION_NAME = "sensorPosition";
/**
* Set common values to procedure description
*
* @param procedure
* Hibernate procedure entity
* @param abstractProcess
* SensorML process
* @param session
* the session
*
* @throws OwsExceptionReport
* If an error occurs
*/
protected void setCommonValues(Procedure procedure, AbstractProcess abstractProcess, Session session)
throws OwsExceptionReport {
setCommonData(procedure, abstractProcess, session);
String identifier = procedure.getIdentifier();
String[] observableProperties = getObservablePropertiesForProcedure(identifier);
// 3 set identification
abstractProcess.setIdentifications(createIdentifications(identifier));
// 7 set inputs/outputs --> observableProperties
if (getServiceConfig().isAddOutputsToSensorML()
&& !"hydrology".equalsIgnoreCase(Configurator.getInstance().getProfileHandler().getActiveProfile()
.getIdentifier())) {
TreeSet<String> obsProps = Sets.newTreeSet(Arrays.asList(observableProperties));
abstractProcess.setInputs(createInputs(obsProps));
abstractProcess.setOutputs(createOutputs(procedure, obsProps, session));
}
}
private List<SmlIo<?>> createInputs(Set<String> observableProperties) throws OwsExceptionReport {
final List<SmlIo<?>> inputs = Lists.newArrayListWithExpectedSize(observableProperties.size());
int i = 1;
for (String observableProperty : observableProperties) {
inputs.add(new SmlIo<String>().setIoName("input#" + i++).setIoValue(getInputComponent(observableProperty)));
}
return inputs;
}
protected abstract SweAbstractDataComponent getInputComponent(String observableProperty);
/**
* Create SensorML output list from observableProperties
*
* @param procedure
* Hibernate procedure entity
* @param observableProperties
* Properties observed by the procedure
*
* @return Output list
*
* @throws OwsExceptionReport
* If an error occurs
*/
private List<SmlIo<?>> createOutputs(Procedure procedure, Set<String> observableProperties, Session session)
throws OwsExceptionReport {
try {
final List<SmlIo<?>> outputs = Lists.newArrayListWithExpectedSize(observableProperties.size());
int i = 1;
final boolean supportsObservationConstellation =
HibernateHelper.isEntitySupported(ObservationConstellation.class);
for (String observableProperty : observableProperties) {
final SmlIo<?> output;
if (supportsObservationConstellation) {
output =
createOutputFromObservationConstellation(procedure.getIdentifier(), observableProperty,
session);
} else {
output =
createOutputFromExampleObservation(procedure.getIdentifier(), observableProperty, session);
}
if (output != null) {
output.setIoName("output#" + i++);
outputs.add(output);
}
}
return outputs;
} catch (final HibernateException he) {
throw new NoApplicableCodeException().causedBy(he).withMessage("Error while querying observation data!")
.setStatus(HTTPStatus.INTERNAL_SERVER_ERROR);
}
}
private SmlIo<?> createOutputFromObservationConstellation(String procedure, String observableProperty,
Session session) throws OwsExceptionReport {
List<ObservationConstellation> observationConstellations =
new ObservationConstellationDAO().getObservationConstellations(procedure, observableProperty, session);
if (CollectionHelper.isNotEmpty(observationConstellations)) {
ObservationConstellation oc = observationConstellations.iterator().next();
String unit = queryUnit(oc, session);
if (oc.isSetObservationType()) {
final String observationType = oc.getObservationType().getObservationType();
if (OmConstants.OBS_TYPE_MEASUREMENT.equals(observationType)) {
final SweQuantity quantity = new SweQuantity();
quantity.setDefinition(observableProperty);
if (StringHelper.isNotEmpty(unit)) {
quantity.setUom(unit);
}
return new SmlIo<Double>(quantity);
} else if (OmConstants.OBS_TYPE_CATEGORY_OBSERVATION.equals(observationType)) {
final SweCategory category = new SweCategory();
category.setDefinition(observableProperty);
if (StringHelper.isNotEmpty(unit)) {
category.setUom(unit);
}
return new SmlIo<String>(category);
} else if (OmConstants.OBS_TYPE_COUNT_OBSERVATION.equals(observationType)) {
return new SmlIo<String>(new SweCategory().setDefinition(observableProperty));
} else if (OmConstants.OBS_TYPE_TEXT_OBSERVATION.equals(observationType)) {
return new SmlIo<String>(new SweText().setDefinition(observableProperty));
} else if (OmConstants.OBS_TYPE_TRUTH_OBSERVATION.equals(observationType)) {
return new SmlIo<Boolean>(new SweBoolean().setDefinition(observableProperty));
} else if (OmConstants.OBS_TYPE_GEOMETRY_OBSERVATION.equals(observationType)) {
// TODO implement GeometryObservation
logTypeNotSupported(OmConstants.OBS_TYPE_GEOMETRY_OBSERVATION);
} else if (OmConstants.OBS_TYPE_COMPLEX_OBSERVATION.equals(observationType)) {
// TODO implement ComplexObservation
logTypeNotSupported(OmConstants.OBS_TYPE_COMPLEX_OBSERVATION);
} else if (OmConstants.OBS_TYPE_UNKNOWN.equals(observationType)) {
// TODO implement UnknownObservation
logTypeNotSupported(OmConstants.OBS_TYPE_UNKNOWN);
} else if (OmConstants.OBS_TYPE_SWE_ARRAY_OBSERVATION.equals(observationType)) {
// TODO implement SWEArrayObservation
logTypeNotSupported(OmConstants.OBS_TYPE_SWE_ARRAY_OBSERVATION);
}
}
}
return null;
}
private String queryUnit(ObservationConstellation oc, Session session) throws OwsExceptionReport {
if (HibernateHelper.isNamedQuerySupported(SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE_OFFERING,
session)) {
Query namedQuery = session.getNamedQuery(SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE_OFFERING);
namedQuery.setParameter(ObservationConstellation.OBSERVABLE_PROPERTY, oc.getObservableProperty()
.getIdentifier());
namedQuery.setParameter(ObservationConstellation.PROCEDURE, oc.getProcedure().getIdentifier());
namedQuery.setParameter(ObservationConstellation.OFFERING, oc.getOffering().getIdentifier());
LOGGER.debug("QUERY queryUnit(observationConstellation) with NamedQuery: {}",
SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE_OFFERING);
return (String) namedQuery.uniqueResult();
} else if (HibernateHelper
.isNamedQuerySupported(SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE, session)) {
Query namedQuery = session.getNamedQuery(SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE);
namedQuery.setParameter(ObservationConstellation.OBSERVABLE_PROPERTY, oc.getObservableProperty()
.getIdentifier());
namedQuery.setParameter(ObservationConstellation.PROCEDURE, oc.getProcedure().getIdentifier());
LOGGER.debug("QUERY queryUnit(observationConstellation) with NamedQuery: {}",
SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY_PROCEDURE);
return (String) namedQuery.uniqueResult();
} else if (HibernateHelper.isNamedQuerySupported(SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY, session)) {
Query namedQuery = session.getNamedQuery(SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY);
namedQuery.setParameter(ObservationConstellation.OBSERVABLE_PROPERTY, oc.getObservableProperty()
.getIdentifier());
LOGGER.debug("QUERY queryUnit(observationConstellation) with NamedQuery: {}",
SQL_QUERY_GET_UNIT_FOR_OBSERVABLE_PROPERTY);
return (String) namedQuery.uniqueResult();
} else if (EntitiyHelper.getInstance().isSeriesSupported()) {
List<Series> series = DaoFactory.getInstance().getSeriesDAO().getSeries(Lists.newArrayList(oc.getProcedure().getIdentifier()), Lists.newArrayList(oc.getObservableProperty().getIdentifier()), Lists.<String>newArrayList(), session);
if (series.iterator().hasNext()) {
Series next = series.iterator().next();
if (next.isSetUnit() ) {
return next.getUnit().getUnit();
}
}
}
AbstractObservation exampleObservation =
getExampleObservation(oc.getProcedure().getIdentifier(), oc.getObservableProperty().getIdentifier(),
session);
if (exampleObservation != null && exampleObservation.isSetUnit()) {
return exampleObservation.getUnit().getUnit();
}
return null;
}
/**
* Logger method for class
*
* @param clazz
* Name of not supported class
*/
private void logTypeNotSupported(Class<?> clazz) {
LOGGER.debug("Type '{}' is not supported by the current implementation", clazz.getName());
}
/**
* Logger method for class
*
* @param observationType
* Name of not supported class
*/
private void logTypeNotSupported(String observationType) {
LOGGER.debug("ObservationType '{}' is not supported by the current implementation", observationType);
}
private SmlIo<?> createOutputFromExampleObservation(String procedure, String observableProperty, Session session)
throws OwsExceptionReport {
final AbstractObservation exampleObservation = getExampleObservation(procedure, observableProperty, session);
if (exampleObservation == null) {
return null;
}
if (exampleObservation instanceof BlobObservation) {
// TODO implement BlobObservations
logTypeNotSupported(BlobObservation.class);
} else if (exampleObservation instanceof BooleanObservation) {
return new SmlIo<Boolean>(new SweBoolean().setDefinition(observableProperty));
} else if (exampleObservation instanceof CategoryObservation) {
final SweCategory category = new SweCategory();
category.setDefinition(observableProperty);
if (exampleObservation.isSetUnit()) {
category.setUom(exampleObservation.getUnit().getUnit());
}
return new SmlIo<String>(category);
} else if (exampleObservation instanceof CountObservation) {
return new SmlIo<Integer>(new SweCount().setDefinition(observableProperty));
} else if (exampleObservation instanceof GeometryObservation) {
// TODO implement GeometryObservations
logTypeNotSupported(GeometryObservation.class);
} else if (exampleObservation instanceof NumericObservation) {
final SweQuantity quantity = new SweQuantity();
quantity.setDefinition(observableProperty);
if (exampleObservation.isSetUnit()) {
quantity.setUom(exampleObservation.getUnit().getUnit());
}
return new SmlIo<Double>(quantity);
} else if (exampleObservation instanceof TextObservation) {
return new SmlIo<String>(new SweText().setDefinition(observableProperty));
}
return null;
}
/**
* Create SensorML Position from Hibernate procedure entity
*
* @param procedure
* Hibernate procedure entity
*
* @return SensorML Position
*/
protected SmlPosition createPosition(Procedure procedure) {
SmlPosition position = new SmlPosition();
position.setName(POSITION_NAME);
position.setFixed(true);
int srid = GeometryHandler.getInstance().getDefaultResponseEPSG();
if (procedure.isSetLongLat()) {
// 8.1 set latlong position
position.setPosition(createCoordinatesForPosition(procedure.getLongitude(), procedure.getLatitude(),
procedure.getAltitude()));
} else if (procedure.isSetGeometry()) {
// 8.2 set position from geometry
if (procedure.getGeom().getSRID() > 0) {
srid = procedure.getGeom().getSRID();
}
final Coordinate c = procedure.getGeom().getCoordinate();
position.setPosition(createCoordinatesForPosition(c.y, c.x, c.z));
}
if (procedure.isSetSrid()) {
srid = procedure.getSrid();
}
position.setReferenceFrame(getServiceConfig().getSrsNamePrefixSosV2() + srid);
return position;
}
/**
* Create SWE Coordinates for SensorML Position
*
* @param longitude
* Longitude value
* @param latitude
* Latitude value
* @param altitude
* Altitude value
*
* @return List with SWE Coordinate
*/
private List<SweCoordinate<?>> createCoordinatesForPosition(Object longitude, Object latitude, Object altitude) {
SweQuantity yq = createSweQuantity(latitude, SweConstants.Y_AXIS, procedureSettings().getLatLongUom());
SweQuantity xq = createSweQuantity(longitude, SweConstants.X_AXIS, procedureSettings().getLatLongUom());
SweQuantity zq = createSweQuantity(altitude, SweConstants.Z_AXIS, procedureSettings().getAltitudeUom());
// TODO add Integer: Which SweSimpleType to use?
return Lists.<SweCoordinate<?>> newArrayList(new SweCoordinate<Double>(SweCoordinateName.northing.name(), yq),
new SweCoordinate<Double>(SweCoordinateName.easting.name(), xq), new SweCoordinate<Double>(
SweCoordinateName.altitude.name(), zq));
}
/**
* Create SWE Quantity for SWE coordinate
*
* @param value
* Value
* @param axis
* Axis id
* @param uom
* UnitOfMeasure
*
* @return SWE Quantity
*/
private SweQuantity createSweQuantity(Object value, String axis, String uom) {
return new SweQuantity().setAxisID(axis).setUom(uom).setValue(JavaHelper.asDouble(value));
}
private List<SmlIdentifier> createIdentifications(final String identifier) {
return Lists.newArrayList(createIdentifier(identifier));
}
private SmlIdentifier createIdentifier(final String identifier) {
return new SmlIdentifier(OGCConstants.URN_UNIQUE_IDENTIFIER_END, OGCConstants.URN_UNIQUE_IDENTIFIER,
identifier);
}
}