/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* Licensed 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.constellation.sos.io.om2;
// J2SE dependencies
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKBReader;
import org.apache.sis.storage.DataStoreException;
import org.constellation.generic.database.Automatic;
import org.constellation.generic.database.BDD;
import org.geotoolkit.gml.JTStoGeometry;
import org.geotoolkit.gml.xml.AbstractGeometry;
import org.geotoolkit.gml.xml.FeatureProperty;
import org.constellation.sos.io.ObservationReader;
import org.geotoolkit.observation.xml.OMXmlFactory;
import org.geotoolkit.referencing.CRS;
import org.geotoolkit.sos.xml.ObservationOffering;
import org.geotoolkit.sos.xml.ResponseModeType;
import org.geotoolkit.sos.xml.SOSXmlFactory;
import org.geotoolkit.swe.xml.AbstractDataRecord;
import org.geotoolkit.swe.xml.AnyScalar;
import org.geotoolkit.swe.xml.DataArrayProperty;
import org.geotoolkit.swe.xml.PhenomenonProperty;
import org.geotoolkit.swe.xml.TextBlock;
import org.geotoolkit.swe.xml.v101.PhenomenonPropertyType;
import org.geotoolkit.util.StringUtilities;
import org.opengis.observation.Observation;
import org.opengis.observation.Phenomenon;
import org.opengis.observation.sampling.SamplingFeature;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.temporal.TemporalGeometricPrimitive;
import org.opengis.temporal.TemporalPrimitive;
import org.opengis.util.FactoryException;
import javax.sql.DataSource;
import javax.xml.namespace.QName;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.constellation.sos.ws.SOSConstants.MEASUREMENT_QNAME;
import static org.constellation.sos.ws.SOSConstants.OBSERVATION_MODEL;
import static org.constellation.sos.ws.SOSConstants.OBSERVATION_QNAME;
import static org.constellation.sos.ws.SOSConstants.RESPONSE_FORMAT_V100;
import static org.constellation.sos.ws.SOSConstants.RESPONSE_FORMAT_V200;
import static org.constellation.sos.ws.SOSConstants.SENSORML_100_FORMAT_V100;
import static org.constellation.sos.ws.SOSConstants.SENSORML_100_FORMAT_V200;
import static org.constellation.sos.ws.SOSConstants.SENSORML_101_FORMAT_V100;
import static org.constellation.sos.ws.SOSConstants.SENSORML_101_FORMAT_V200;
import org.geotoolkit.gml.xml.TimeIndeterminateValueType;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildDataArrayProperty;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildFeatureProperty;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildMeasure;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildOffering;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildSimpleDatarecord;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildTimeInstant;
import static org.geotoolkit.sos.xml.SOSXmlFactory.buildTimePeriod;
import static org.geotoolkit.sos.xml.SOSXmlFactory.getDefaultTextEncoding;
import static org.geotoolkit.sos.xml.SOSXmlFactory.getGMLVersion;
import org.opengis.temporal.IndeterminateValue;
/**
* Default Observation reader for Postgrid O&M database.
*
* @author Guilhem Legal
*/
public class OM2ObservationReader extends OM2BaseReader implements ObservationReader {
protected final DataSource source;
private static final Map<String, List<String>> RESPONSE_FORMAT = new HashMap<>();
static {
RESPONSE_FORMAT.put("1.0.0", Arrays.asList(RESPONSE_FORMAT_V100));
RESPONSE_FORMAT.put("2.0.0", Arrays.asList(RESPONSE_FORMAT_V200));
}
private final Map<String, List<String>> acceptedSensorMLFormats = new HashMap<>();
/**
*
* @param configuration
* @param properties
* @throws org.apache.sis.storage.DataStoreException
*/
@Deprecated
public OM2ObservationReader(final Automatic configuration, final String schemaPrefix, final Map<String, Object> properties) throws DataStoreException {
super(properties, schemaPrefix);
if (configuration == null) {
throw new DataStoreException("The configuration object is null");
}
// we get the database informations
final BDD db = configuration.getBdd();
if (db == null) {
throw new DataStoreException("The configuration file does not contains a BDD object (DefaultObservationReader)");
}
isPostgres = db.getClassName() != null && db.getClassName().equals("org.postgresql.Driver");
try {
this.source = db.getDataSource();
// try if the connection is valid
try(final Connection c = this.source.getConnection()) {}
} catch (SQLException ex) {
throw new DataStoreException(ex);
}
final String smlFormats100 = (String) properties.get("smlFormats100");
if (smlFormats100 != null) {
acceptedSensorMLFormats.put("1.0.0", StringUtilities.toStringList(smlFormats100));
} else {
acceptedSensorMLFormats.put("1.0.0", Arrays.asList(SENSORML_100_FORMAT_V100,
SENSORML_101_FORMAT_V100));
}
final String smlFormats200 = (String) properties.get("smlFormats200");
if (smlFormats200 != null) {
acceptedSensorMLFormats.put("2.0.0", StringUtilities.toStringList(smlFormats200));
} else {
acceptedSensorMLFormats.put("2.0.0", Arrays.asList(SENSORML_100_FORMAT_V200,
SENSORML_101_FORMAT_V200));
}
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getOfferingNames(final String version) throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement()) {
final List<String> results = new ArrayList<>();
try(final ResultSet rs = stmt.executeQuery("SELECT \"identifier\" FROM \"" + schemaPrefix + "om\".\"offerings\"")) {
while (rs.next()) {
results.add(rs.getString(1));
}
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving offering names.", ex);
}
}
@Override
public List<String> getOfferingNames(final String version, final String sensorType) throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement()) {
final List<String> results = new ArrayList<>();
String query;
if (sensorType != null) {
query = "SELECT \"identifier\" FROM \"om\".\"offerings\" o, \"om\".\"procedures\" p WHERE o.\"procedure\" = p.\"id\" AND p.\"type\" = '" + sensorType + "'";
} else {
query = "SELECT \"identifier\" FROM \"om\".\"offerings\"";
}
try (final ResultSet rs = stmt.executeQuery(query)) {
while (rs.next()) {
results.add(rs.getString(1));
}
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving offering names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<ObservationOffering> getObservationOfferings(final List<String> offeringNames, final String version) throws DataStoreException {
final List<ObservationOffering> offerings = new ArrayList<>();
for (String offeringName : offeringNames) {
offerings.add(getObservationOffering(offeringName, version));
}
return offerings;
}
/**
* {@inheritDoc}
*/
@Override
public ObservationOffering getObservationOffering(final String offeringName, final String version) throws DataStoreException {
final String id;
final String name;
final String description;
final TemporalGeometricPrimitive time;
final String procedure;
final List<String> phen200 = new ArrayList<>();
final List<PhenomenonProperty> phen100 = new ArrayList<>();
final List<String> foi = new ArrayList<>();
try(final Connection c = source.getConnection()) {
try(final PreparedStatement stmt = c.prepareStatement("SELECT * FROM \"" + schemaPrefix + "om\".\"offerings\" WHERE \"identifier\"=?")) {
stmt.setString(1, offeringName);
try(final ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
id = rs.getString(1);
description = rs.getString(2);
name = rs.getString(3);
final Timestamp b = rs.getTimestamp(4);
final Timestamp e = rs.getTimestamp(5);
procedure = rs.getString(6);
if (b != null && e == null) {
time = buildTimePeriod(version, b, (TimeIndeterminateValueType)null);
} else if (b != null && e != null) {
time = buildTimePeriod(version, b, e);
} else {
time = null;
}
} else {
return null;
}
}
try(final PreparedStatement stmt2 = c.prepareStatement("SELECT \"phenomenon\" FROM \"" + schemaPrefix + "om\".\"offering_observed_properties\" WHERE \"id_offering\"=?")) {
stmt2.setString(1, offeringName);
try(final ResultSet rs2 = stmt2.executeQuery()) {
while (rs2.next()) {
final String href = rs2.getString(1);
phen200.add(href);
phen100.add(new PhenomenonPropertyType(href));
}
}
}
try(final PreparedStatement stmt3 = c.prepareStatement("SELECT \"foi\" FROM \"" + schemaPrefix + "om\".\"offering_foi\" WHERE \"id_offering\"=?")) {
stmt3.setString(1, offeringName);
try(final ResultSet rs3 = stmt3.executeQuery()) {
while (rs3.next()) {
foi.add(rs3.getString(1));
}
}
}
}
final List<String> responseFormat = RESPONSE_FORMAT.get(version);
final List<QName> resultModel = Arrays.asList(OBSERVATION_QNAME, MEASUREMENT_QNAME);
final List<String> resultModelV200 = Arrays.asList(OBSERVATION_MODEL);
final List<ResponseModeType> responseMode = Arrays.asList(ResponseModeType.INLINE, ResponseModeType.RESULT_TEMPLATE);
final List<String> procedureDescription = acceptedSensorMLFormats.get("2.0.0");
return buildOffering(version,
id,
name,
description,
null,
time,
Arrays.asList(procedure),
phen100,
phen200,
foi,
responseFormat,
resultModel,
resultModelV200,
responseMode,
procedureDescription);
} catch (SQLException e) {
throw new DataStoreException("Error while retrieving offering names.", e);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<ObservationOffering> getObservationOfferings(final String version) throws DataStoreException {
final List<String> offeringNames = getOfferingNames(version);
final List<ObservationOffering> loo = new ArrayList<>();
for (String offeringName : offeringNames) {
loo.add(getObservationOffering(offeringName, version));
}
return loo;
}
@Override
public List<ObservationOffering> getObservationOfferings(final String version, final String sensorType) throws DataStoreException {
final List<String> offeringNames = getOfferingNames(version, sensorType);
final List<ObservationOffering> loo = new ArrayList<>();
for (String offeringName : offeringNames) {
loo.add(getObservationOffering(offeringName, version));
}
return loo;
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getProcedureNames() throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT \"id\" FROM \"" + schemaPrefix + "om\".\"procedures\"")) {
final List<String> results = new ArrayList<>();
while (rs.next()) {
results.add(rs.getString(1));
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving procedure names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getProcedureNames(final String sensorType) throws DataStoreException {
String filter = "";
if (sensorType != null) {
filter = " WHERE \"type\"='" + sensorType + "'";
}
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT \"id\" FROM \"om\".\"procedures\"" + filter)) {
final List<String> results = new ArrayList<>();
while (rs.next()) {
results.add(rs.getString(1));
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving procedure names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getPhenomenonNames() throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT \"id\" FROM \"" + schemaPrefix + "om\".\"observed_properties\"")) {
final List<String> results = new ArrayList<>();
while (rs.next()) {
results.add(rs.getString(1));
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving phenomenon names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public Collection<String> getProceduresForPhenomenon(final String observedProperty) throws DataStoreException {
try(final Connection c = source.getConnection();
final PreparedStatement stmt = c.prepareStatement("SELECT DISTINCT \"procedure\" "
+ "FROM \"" + schemaPrefix + "om\".\"offerings\", \"" + schemaPrefix + "om\".\"offering_observed_properties\""
+ "WHERE \"identifier\"=\"id_offering\""
+ "AND \"phenomenon\"=?")) {
final List<String> results = new ArrayList<>();
stmt.setString(1, observedProperty);
try(final ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
results.add(rs.getString(1));
}
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving procedure names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public Collection<String> getPhenomenonsForProcedure(final String sensorID) throws DataStoreException {
try(final Connection c = source.getConnection();
final PreparedStatement stmt = c.prepareStatement("SELECT \"phenomenon\" "
+ "FROM \"" + schemaPrefix + "om\".\"offerings\", \"" + schemaPrefix + "om\".\"offering_observed_properties\""
+ "WHERE \"identifier\"=\"id_offering\""
+ "AND \"procedure\"=?")) {
final Set<String> results = new HashSet<>();
stmt.setString(1, sensorID);
try(final ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
results.add(rs.getString(1));
}
}
//look for composite phenomenons
try(final PreparedStatement stmtC = c.prepareStatement("SELECT \"component\" "
+ "FROM \"" + schemaPrefix + "om\".\"components\""
+ "WHERE \"phenomenon\"=?")) {
final Set<String> toAdd = new HashSet<>();
final Set<String> toRemove = new HashSet<>();
for (Iterator<String> it = results.iterator(); it.hasNext();) {
String pheno = it.next();
stmtC.setString(1, pheno);
try(final ResultSet rsC = stmtC.executeQuery()) {
boolean composite = false;
while (rsC.next()) {
composite = true;
toAdd.add(rsC.getString(1));
}
if (composite) {
toRemove.add(pheno);
}
}
}
results.addAll(toAdd);
results.removeAll(toRemove);
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving procedure names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean existPhenomenon(final String phenomenonName) throws DataStoreException {
return getPhenomenonNames().contains(phenomenonName);
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getFeatureOfInterestNames() throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT \"id\" FROM \"" + schemaPrefix + "om\".\"sampling_features\"")) {
final List<String> results = new ArrayList<>();
while (rs.next()) {
results.add(rs.getString(1));
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving phenomenon names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public SamplingFeature getFeatureOfInterest(final String samplingFeatureName, final String version) throws DataStoreException {
try(final Connection c = source.getConnection()) {
return getFeatureOfInterest(samplingFeatureName, version, c);
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
@Override
public AbstractGeometry getSensorLocation(final String sensorID, final String version) throws DataStoreException {
try(final Connection c = source.getConnection()) {
final byte[] b;
final int srid;
try(final PreparedStatement stmt = (isPostgres) ?
c.prepareStatement("SELECT st_asBinary(\"shape\"), \"crs\" FROM \"" + schemaPrefix + "om\".\"procedures\" WHERE \"id\"=?") :
c.prepareStatement("SELECT \"shape\", \"crs\" FROM \"" + schemaPrefix + "om\".\"procedures\" WHERE \"id\"=?")) {
stmt.setString(1, sensorID);
try(final ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
b = rs.getBytes(1);
srid = rs.getInt(2);
} else {
return null;
}
}
}
final CoordinateReferenceSystem crs;
if (srid != 0) {
crs = CRS.decode("urn:ogc:def:crs:EPSG:" + srid);
} else {
crs = defaultCRS;
}
final Geometry geom;
if (b != null) {
WKBReader reader = new WKBReader();
geom = reader.read(b);
} else {
return null;
}
final String gmlVersion = getGMLVersion(version);
return JTStoGeometry.toGML(gmlVersion, geom, crs);
} catch (SQLException | FactoryException | ParseException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public TemporalGeometricPrimitive getTimeForProcedure(final String version, final String sensorID) throws DataStoreException {
TemporalGeometricPrimitive result = null;
try(final Connection c = source.getConnection();
final PreparedStatement stmt = c.prepareStatement("SELECT \"time_begin\", \"time_end\" "
+ "FROM \"" + schemaPrefix + "om\".\"offerings\" "
+ "WHERE \"procedure\"=?")) {
stmt.setString(1, sensorID);
try(final ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
final Timestamp begin = rs.getTimestamp(1);
final Timestamp end = rs.getTimestamp(2);
if (begin != null && end == null) {
result = SOSXmlFactory.buildTimeInstant(version, begin);
} else if (begin == null && end != null) {
result = SOSXmlFactory.buildTimeInstant(version, begin);
} else if (begin != null && end != null) {
result = SOSXmlFactory.buildTimePeriod(version, begin, end);
}
}
}
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving procedure time.", ex);
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public Observation getObservation(String identifier, final QName resultModel, final ResponseModeType mode, final String version) throws DataStoreException {
try(final Connection c = source.getConnection()) {
final String observationID;
if (identifier.startsWith(observationIdBase)) {
observationID = identifier.substring(observationIdBase.length());
} else if (identifier.startsWith(observationTemplateIdBase)) {
final String procedureID = sensorIdBase + identifier.substring(observationTemplateIdBase.length());
try(final PreparedStatement stmt = c.prepareStatement("SELECT \"id\", \"identifier\" FROM \"" + schemaPrefix + "om\".\"observations\" WHERE \"procedure\"=?")) {
stmt.setString(1, procedureID);
try(final ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
observationID = rs.getString(1);
identifier = rs.getString(2);
} else {
return null;
}
}
}
} else {
observationID = identifier;
}
final String obsID = "obs-" + observationID;
final String timeID = "time-" + observationID;
final String observedProperty;
final String procedure;
final String foi;
final TemporalGeometricPrimitive time;
try(final PreparedStatement stmt = c.prepareStatement("SELECT * FROM \"" + schemaPrefix + "om\".\"observations\" WHERE \"identifier\"=?")) {
stmt.setString(1, identifier);
try(final ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
final String b = rs.getString(3);
final String e = rs.getString(4);
if (b != null && e == null) {
time = buildTimeInstant(version, timeID, b.replace(' ', 'T'));
} else if (b != null && e != null) {
time = buildTimePeriod(version, timeID, b.replace(' ', 'T'), e.replace(' ', 'T'));
} else {
time = null;
}
observedProperty = rs.getString(5);
procedure = rs.getString(6);
foi = rs.getString(7);
} else {
return null;
}
}
}
final SamplingFeature feature = getFeatureOfInterest(foi, version, c);
final FeatureProperty prop = buildFeatureProperty(version, feature);
final Phenomenon phen = getPhenomenon(version, observedProperty, c);
final String name;
if (ResponseModeType.RESULT_TEMPLATE.equals(mode)) {
final String procedureID = procedure.substring(sensorIdBase.length());
name = observationTemplateIdBase + procedureID;
} else {
name = identifier;
}
if (resultModel.equals(MEASUREMENT_QNAME)) {
final Object result = getResult(identifier, resultModel, version);
return OMXmlFactory.buildMeasurement(version, obsID, name, null, prop, phen, procedure, result, time);
} else {
final Object result = getResult(identifier, resultModel, version);
return OMXmlFactory.buildObservation(version, obsID, name, null, prop, phen, procedure, result, time);
}
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public Object getResult(final String identifier, final QName resultModel, final String version) throws DataStoreException {
try(final Connection c = source.getConnection()) {
return getResult(identifier, resultModel, version, c);
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
private Object getResult(final String identifier, final QName resultModel, final String version, final Connection c) throws DataStoreException, SQLException {
if (resultModel.equals(MEASUREMENT_QNAME)) {
return buildMeasureResult(identifier, version, c);
} else {
return buildComplexResult2(identifier, version, c);
}
}
private DataArrayProperty buildComplexResult2(final String identifier, final String version, final Connection c) throws DataStoreException, SQLException {
final int pid = getPIDFromObservation(identifier, c);
final String procedure = getProcedureFromObservation(identifier, c);
final List<Field> fields = readFields(procedure, c);
final String arrayID = "dataArray-1"; // TODO
final String recordID = "datarecord-0"; // TODO
final TextBlock encoding = getDefaultTextEncoding(version);
final List<AnyScalar> scal = new ArrayList<>();
for (Field f : fields) {
scal.add(f.getScalar(version));
}
int nbValue = 0;
final StringBuilder values = new StringBuilder();
try(final PreparedStatement stmt = c.prepareStatement("SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m, \"" + schemaPrefix + "om\".\"observations\" o "
+ "WHERE \"id_observation\" = o.\"id\" "
+ "AND o.\"identifier\"=?"
+ "ORDER BY m.\"id\"")) {
stmt.setString(1, identifier);
try(final ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
for (int i = 0; i < fields.size(); i++) {
String value = rs.getString(i + 3);
Field field = fields.get(i);
// for time TODO remove when field will be typed
if (field.fieldType.equals("Time")) {
value = value.replace(' ', 'T');
value = value.substring(0, value.length() - 2);
}
values.append(value).append(encoding.getTokenSeparator());
}
values.deleteCharAt(values.length() - 1);
values.append(encoding.getBlockSeparator());
nbValue++;
}
}
}
final AbstractDataRecord record = buildSimpleDatarecord(version, null, recordID, null, false, scal);
return buildDataArrayProperty(version, arrayID, nbValue, arrayID, record, encoding, values.toString());
}
private Object buildMeasureResult(final String identifier, final String version, final Connection c) throws DataStoreException, SQLException {
final int pid = getPIDFromObservation(identifier, c);
final String procedure = getProcedureFromObservation(identifier, c);
final List<Field> fields = readFields(procedure, c);
final String uom = fields.get(0).fieldUom;
final double value;
final String name;
try(final PreparedStatement stmt = c.prepareStatement("SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m, \"" + schemaPrefix + "om\".\"observations\" o "
+ "WHERE \"id_observation\" = o.\"id\" "
+ "AND o.\"identifier\"=?"
+ "ORDER BY m.\"id\"")) {
stmt.setString(1, identifier);
try(final ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
name = "measure-00" + rs.getString("id");
value = Double.parseDouble(rs.getString(3));
} else {
return null;
}
}
} catch (NumberFormatException ex) {
throw new DataStoreException("Unable ta parse the result value as a double");
}
return buildMeasure(version, name, uom, value);
}
/**
* {@inheritDoc}
*/
@Override
public Observation getTemplateForProcedure(final String procedure, final String version) throws DataStoreException {
// TODO generate template from procedue description
Observation template = null;
try(final Connection c = source.getConnection()) {
try(final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT \"identifier\" FROM \"" + schemaPrefix + "om\".\"observations\" WHERE \"procedure\"='" + procedure + "'")) {
String identifier = null;
if (rs.next()) {
identifier = rs.getString(1);
}
if (identifier != null) {
template = getObservation(identifier, OBSERVATION_QNAME, ResponseModeType.RESULT_TEMPLATE, version);
}
}
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
return template;
}
/**
* {@inheritDoc}
*/
@Override
public boolean existProcedure(final String href) throws DataStoreException {
return getProcedureNames().contains(href);
}
/**
* {@inheritDoc}
*/
@Override
public void destroy() {
// do nothing
}
/**
* {@inheritDoc}
*/
@Override
public String getNewObservationId() throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT max(\"id\") FROM \"" + schemaPrefix + "om\".\"observations\"")) {
int resultNum;
if (rs.next()) {
resultNum = rs.getInt(1) + 1;
} else {
resultNum = 1;
}
return observationIdBase + resultNum;
} catch (SQLException ex) {
throw new DataStoreException("Error while looking for available observation id.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public TemporalPrimitive getFeatureOfInterestTime(final String samplingFeatureName, final String version) throws DataStoreException {
try(final Connection c = source.getConnection();
final PreparedStatement stmt = c.prepareStatement("SELECT min(\"time_begin\"), max(\"time_end\") "
+ "FROM \"" + schemaPrefix + "om\".\"observations\""
+ "WHERE \"foi\"=?")) {
stmt.setString(1, samplingFeatureName);
try (final ResultSet rs = stmt.executeQuery()) {
final TemporalGeometricPrimitive time;
if (rs.next()) {
final Timestamp b = rs.getTimestamp(1);
final Timestamp e = rs.getTimestamp(2);
if (b != null && e == null) {
time = buildTimeInstant(version, b);
} else if (b != null && e != null) {
time = buildTimePeriod(version, b, e);
} else {
time = null;
}
} else {
time = null;
}
return time;
}
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving phenomenon names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getEventTime() throws DataStoreException {
try(final Connection c = source.getConnection();
final Statement stmt = c.createStatement();
final ResultSet rs = stmt.executeQuery("SELECT max(\"time_begin\"), min(\"time_end\") FROM \"" + schemaPrefix + "om\".\"offerings\"")) {
final List<String> results = new ArrayList<>();
if (rs.next()) {
String s = rs.getString(1);
if (s != null) {
results.add(s);
}
s = rs.getString(2);
if (s != null) {
results.add(s);
}
}
return results;
} catch (SQLException ex) {
throw new DataStoreException("Error while retrieving phenomenon names.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public String getInfos() {
return "Constellation O&M 2 Reader 0.9";
}
/**
* {@inheritDoc}
*/
@Override
public List<ResponseModeType> getResponseModes() throws DataStoreException {
return Arrays.asList(ResponseModeType.INLINE, ResponseModeType.RESULT_TEMPLATE);
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getResponseFormats() throws DataStoreException {
return Arrays.asList(RESPONSE_FORMAT_V100, RESPONSE_FORMAT_V200);
}
}