/* * 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; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKBReader; 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.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import org.apache.sis.storage.DataStoreException; import org.constellation.generic.database.Automatic; import static org.constellation.sos.ws.SOSConstants.EVENT_TIME; import static org.constellation.sos.ws.SOSConstants.MEASUREMENT_QNAME; import static org.constellation.sos.ws.SOSConstants.RESPONSE_MODE; import static org.constellation.sos.ws.SOSUtils.getTimeValue; import org.geotoolkit.geometry.jts.SRIDGenerator; import org.geotoolkit.gml.xml.Envelope; import org.geotoolkit.gml.xml.FeatureProperty; import org.geotoolkit.observation.ObservationFilterReader; import org.geotoolkit.observation.ObservationStoreException; import org.geotoolkit.observation.xml.AbstractObservation; import org.geotoolkit.observation.xml.OMXmlFactory; import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_PARAMETER_VALUE; import static org.geotoolkit.ows.xml.OWSExceptionCode.NO_APPLICABLE_CODE; import org.geotoolkit.referencing.CRS; import static org.geotoolkit.sos.xml.SOSXmlFactory.*; import org.geotoolkit.swe.xml.AbstractDataRecord; import org.geotoolkit.swe.xml.AnyScalar; import org.geotoolkit.swe.xml.DataArray; import org.geotoolkit.swe.xml.DataArrayProperty; import org.geotoolkit.swe.xml.TextBlock; 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.Instant; import org.opengis.temporal.Period; import org.opengis.temporal.TemporalGeometricPrimitive; import org.opengis.util.FactoryException; /** * * @author Guilhem Legal (Geomatys) */ public class OM2ObservationFilterReader extends OM2ObservationFilter implements ObservationFilterReader { private String responseFormat; public OM2ObservationFilterReader(final OM2ObservationFilter omFilter) { super(omFilter); } public OM2ObservationFilterReader(final Automatic configuration, final String schemaPrefix, final Map<String, Object> properties) throws DataStoreException { super(configuration, schemaPrefix, properties); } /** * {@inheritDoc} */ @Override public void setTimeEquals(final Object time) throws DataStoreException { if (time instanceof Period) { final Period tp = (Period) time; final String begin = getTimeValue(tp.getBeginning().getDate()); final String end = getTimeValue(tp.getEnding().getDate()); // we request directly a multiple observation or a period observation (one measure during a period) sqlRequest.append("AND ("); sqlRequest.append(" \"time_begin\"='").append(begin).append("' AND "); sqlRequest.append(" \"time_end\"='").append(end).append("') "); // if the temporal object is a timeInstant } else if (time instanceof Instant) { final Instant ti = (Instant) time; final String position = getTimeValue(ti.getDate()); //sqlRequest.append("AND (\"time_begin\"='").append(position).append("' AND \"time_end\"='").append(position).append("') "); sqlMeasureRequest.append("AND (\"$time\"='").append(position).append("') "); } else { throw new ObservationStoreException("TM_Equals operation require timeInstant or TimePeriod!", INVALID_PARAMETER_VALUE, EVENT_TIME); } } /** * {@inheritDoc} */ @Override public void setTimeBefore(final Object time) throws DataStoreException { // for the operation before the temporal object must be an timeInstant if (time instanceof Instant) { final Instant ti = (Instant) time; final String position = getTimeValue(ti.getDate()); sqlRequest.append("AND (\"time_begin\"<='").append(position).append("')"); sqlMeasureRequest.append("AND (\"$time\"<='").append(position).append("')"); } else { throw new ObservationStoreException("TM_Before operation require timeInstant!", INVALID_PARAMETER_VALUE, EVENT_TIME); } } /** * {@inheritDoc} */ @Override public void setTimeAfter(final Object time) throws DataStoreException { // for the operation after the temporal object must be an timeInstant if (time instanceof Instant) { final Instant ti = (Instant) time; final String position = getTimeValue(ti.getDate()); sqlRequest.append("AND (\"time_end\">='").append(position).append("')"); sqlMeasureRequest.append("AND (\"$time\">='").append(position).append("')"); } else { throw new ObservationStoreException("TM_After operation require timeInstant!", INVALID_PARAMETER_VALUE, EVENT_TIME); } } /** * {@inheritDoc} */ @Override public void setTimeDuring(final Object time) throws DataStoreException { if (time instanceof Period) { final Period tp = (Period) time; final String begin = getTimeValue(tp.getBeginning().getDate()); final String end = getTimeValue(tp.getEnding().getDate()); sqlRequest.append("AND ("); // the multiple observations included in the period sqlRequest.append(" (\"time_begin\">='").append(begin).append("' AND \"time_end\"<='").append(end).append("')"); sqlRequest.append("OR"); // the single observations included in the period sqlRequest.append(" (\"time_begin\">='").append(begin).append("' AND \"time_begin\">='").append(end).append("' AND \"time_end\" IS NULL)"); sqlRequest.append("OR"); // the multiple observations which overlaps the first bound sqlRequest.append(" (\"time_begin\"<='").append(begin).append("' AND \"time_end\"<='").append(end).append("' AND \"time_end\">='").append(begin).append("')"); sqlRequest.append("OR"); // the multiple observations which overlaps the second bound sqlRequest.append(" (\"time_begin\">='").append(begin).append("' AND \"time_end\">='").append(end).append("' AND \"time_begin\"<='").append(end).append("')"); sqlRequest.append("OR"); // the multiple observations which overlaps the whole period sqlRequest.append(" (\"time_begin\"<='").append(begin).append("' AND \"time_end\">='").append(end).append("'))"); sqlMeasureRequest.append("AND (\"$time\">='").append(begin).append("' AND \"$time\"<= '").append(end).append("')"); } else { throw new ObservationStoreException("TM_During operation require TimePeriod!", INVALID_PARAMETER_VALUE, EVENT_TIME); } } @Override public List<Observation> getObservationTemplates(final String version) throws DataStoreException { if (resultModel.equals(MEASUREMENT_QNAME)) { return getMesurementTemplates(version); } try(final Connection c = source.getConnection()) { final Map<String, Observation> observations = new HashMap<>(); try(final Statement currentStatement = c.createStatement(); final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString())) { final TextBlock encoding = getDefaultTextEncoding(version); while (rs.next()) { final String procedure = rs.getString("procedure"); Observation observation = observations.get(procedure); if (observation == null) { final String procedureID = procedure.substring(sensorIdBase.length()); final String obsID = "obs-" + procedureID; final String name = observationTemplateIdBase + procedureID; final String featureID = rs.getString("foi"); final String observedProperty = rs.getString("observed_property"); final SamplingFeature feature = getFeatureOfInterest(featureID, version, c); final FeatureProperty prop = buildFeatureProperty(version, feature); final Phenomenon phen = getPhenomenon(version, observedProperty, c); List<Field> fields = readFields(procedure, c); /* * BUILD RESULT */ final List<AnyScalar> scal = new ArrayList<>(); for (Field f : fields) { scal.add(f.getScalar(version)); } final Object result = buildComplexResult(version, scal, 0, encoding, null, observations.size() - 1); observation = OMXmlFactory.buildObservation(version, obsID, name, null, prop, phen, procedure, result, null); observations.put(procedure, observation); } } } return new ArrayList<>(observations.values()); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage(), ex); } catch (DataStoreException ex) { throw new DataStoreException("the service has throw a Datastore Exception:" + ex.getMessage(), ex); } } public List<Observation> getMesurementTemplates(final String version) throws DataStoreException { try(final Connection c = source.getConnection()) { final Map<String, Observation> observations = new HashMap<>(); try(final Statement currentStatement = c.createStatement(); final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString())) { while (rs.next()) { final String procedure = rs.getString("procedure"); final Observation observation = observations.get(procedure); if (observation == null) { final String procedureID = procedure.substring(sensorIdBase.length()); final String obsID = "obs-" + procedureID; final String name = observationTemplateIdBase + procedureID; final String featureID = rs.getString("foi"); final String observedProperty = rs.getString("observed_property"); final SamplingFeature feature = getFeatureOfInterest(featureID, version, c); final FeatureProperty prop = buildFeatureProperty(version, feature); final Phenomenon phen = getPhenomenon(version, observedProperty, c); /* * BUILD RESULT */ final List<Field> fields = readFields(procedure, c); final Object result = buildMeasureResult(version, 0, fields.get(1).fieldUom, "1"); observations.put(procedure, OMXmlFactory.buildMeasurement(version, obsID, name, null, prop, phen, procedure, result, null)); } else { LOGGER.log(Level.WARNING, "multiple fields on Mesurement for :{0}", procedure); } } } return new ArrayList<>(observations.values()); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage()); } catch (DataStoreException ex) { throw new DataStoreException("the service has throw a Datastore Exception:" + ex.getMessage()); } } @Override public List<Observation> getObservations(final String version) throws DataStoreException { if (resultModel.equals(MEASUREMENT_QNAME)) { return getMesurements(version); } try(final Connection c = source.getConnection(); final Statement currentStatement = c.createStatement()) { try(final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString())) { // add orderby to the query sqlRequest.append(" ORDER BY o.\"id\""); final Map<String, Observation> observations = new HashMap<>(); final TextBlock encoding = getDefaultTextEncoding(version); final Map<String, List<Field>> fieldMap = new LinkedHashMap<>(); while (rs.next()) { int nbValue = 0; StringBuilder values = new StringBuilder(); final String procedure = rs.getString("procedure"); final String featureID = rs.getString("foi"); final int oid = rs.getInt("id"); Observation observation = observations.get(procedure + '-' + featureID); final int pid = getPIDFromProcedure(procedure, c); List<Field> fields = fieldMap.get(procedure); if (fields == null) { fields = readFields(procedure, c); fieldMap.put(procedure, fields); } if (observation == null) { final String obsID = "obs-" + oid; final String timeID = "time-" + oid; final String name = rs.getString("identifier"); final String observedProperty = rs.getString("observed_property"); final SamplingFeature feature = getFeatureOfInterest(featureID, version, c); final FeatureProperty prop = buildFeatureProperty(version, feature); final Phenomenon phen = getPhenomenon(version, observedProperty, c); String firstTime = formatTime(rs.getString("time_begin")); String lastTime = formatTime(rs.getString("time_end")); boolean first = true; final List<AnyScalar> scal = new ArrayList<>(); for (Field f : fields) { scal.add(f.getScalar(version)); } /* * BUILD RESULT */ final Field timeField = getTimeField(procedure); final String sqlRequest; if (timeField != null) { sqlRequest = "SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m " + "WHERE \"id_observation\" = ? " + sqlMeasureRequest.toString().replace("$time", timeField.fieldName) + "ORDER BY m.\"id\""; } else { sqlRequest = "SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m WHERE \"id_observation\" = ? ORDER BY m.\"id\""; } try(final PreparedStatement stmt = c.prepareStatement(sqlRequest)) { stmt.setInt(1, oid); try(final ResultSet rs2 = stmt.executeQuery()) { while (rs2.next()) { for (int i = 0; i < fields.size(); i++) { String value = rs2.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'); if (first) { firstTime = value; first = false; } lastTime = value; value = value.substring(0, value.length() - 2); } values.append(value).append(encoding.getTokenSeparator()); } values.deleteCharAt(values.length() - 1); values.append(encoding.getBlockSeparator()); nbValue++; } } } final TemporalGeometricPrimitive time = buildTimePeriod(version, timeID, firstTime, lastTime); final Object result = buildComplexResult(version, scal, nbValue, encoding, values.toString(), observations.size() - 1); observation = OMXmlFactory.buildObservation(version, obsID, name, null, prop, phen, procedure, result, time); observations.put(procedure + '-' + featureID, observation); } else { String lastTime = null; final Field timeField = getTimeField(procedure); final String sqlRequest; if (timeField != null) { sqlRequest = "SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m " + "WHERE \"id_observation\" = ? " + sqlMeasureRequest.toString().replace("$time", timeField.fieldName) + "ORDER BY m.\"id\""; } else { sqlRequest = "SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m WHERE \"id_observation\" = ? ORDER BY m.\"id\""; } try(final PreparedStatement stmt = c.prepareStatement(sqlRequest)) { stmt.setInt(1, oid); try(final ResultSet rs2 = stmt.executeQuery()) { while (rs2.next()) { for (int i = 0; i < fields.size(); i++) { String value = rs2.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); lastTime = value; } values.append(value).append(encoding.getTokenSeparator()); } values.deleteCharAt(values.length() - 1); values.append(encoding.getBlockSeparator()); nbValue++; } } } // UPDATE RESULTS final DataArrayProperty result = (DataArrayProperty) (observation).getResult(); final DataArray array = result.getDataArray(); array.setElementCount(array.getElementCount().getCount().getValue() + nbValue); array.setValues(array.getValues() + values.toString()); ((AbstractObservation) observation).extendSamplingTime(lastTime); } } return new ArrayList<>(observations.values()); } } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage(), ex); } catch (DataStoreException ex) { throw new DataStoreException("the service has throw a Datastore Exception:" + ex.getMessage(), ex); } } private String formatTime(String s) { if (s != null) { s = s.replace(' ', 'T'); } return s; } private DataArrayProperty buildComplexResult(final String version, final Collection<AnyScalar> fields, final int nbValue, final TextBlock encoding, final String values, final int cpt) { final String arrayID = "dataArray-" + cpt; final String recordID = "datarecord-" + cpt; final AbstractDataRecord record = buildSimpleDatarecord(version, null, recordID, null, false, new ArrayList<>(fields)); return buildDataArrayProperty(version, arrayID, nbValue, arrayID, record, encoding, values); } public List<Observation> getMesurements(final String version) throws DataStoreException { // add orderby to the query sqlRequest.append(" ORDER BY o.\"id\""); try(final Connection c = source.getConnection()) { final List<Observation> observations = new ArrayList<>(); try(final Statement currentStatement = c.createStatement(); final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString())) { while (rs.next()) { final String procedure = rs.getString("procedure"); final Timestamp startTime = rs.getTimestamp("time_begin"); final Timestamp endTime = rs.getTimestamp("time_end"); final int oid = rs.getInt("id"); final String name = rs.getString("identifier"); final String obsID = "obs-" + oid; final String timeID = "time-" + oid; final String featureID = rs.getString("foi"); final String observedProperty = rs.getString("observed_property"); final SamplingFeature feature = getFeatureOfInterest(featureID, version, c); final FeatureProperty prop = buildFeatureProperty(version, feature); final Phenomenon phen = getPhenomenon(version, observedProperty, c); final int pid = getPIDFromProcedure(procedure, c); final List<Field> fields = readFields(procedure, c); final String uom = fields.get(0).fieldUom; String start = null; if (startTime != null) { start = format2.format(startTime); } String end = null; if (endTime != null) { end = format2.format(endTime); } TemporalGeometricPrimitive time = null; if (start != null || end != null) { time = buildTimePeriod(version, timeID, start, end); } /* * BUILD RESULT */ final Field timeField = getTimeField(procedure); final String sqlRequest; if (timeField != null) { sqlRequest = "SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m " + "WHERE \"id_observation\" = ? " + sqlMeasureRequest.toString().replace("$time", timeField.fieldName) + "ORDER BY m.\"id\""; } else { sqlRequest = "SELECT * FROM \"" + schemaPrefix + "mesures\".\"mesure" + pid + "\" m WHERE \"id_observation\" = ? ORDER BY m.\"id\""; } try(final PreparedStatement stmt = c.prepareStatement(sqlRequest)) { stmt.setInt(1, oid); try(final ResultSet rs2 = stmt.executeQuery()) { if (rs2.next()) { Double dValue = null; String rid = null; rid = rs2.getString("id"); final String value = rs2.getString(3); try { dValue = Double.parseDouble(value); } catch (NumberFormatException ex) { throw new DataStoreException("Unable ta parse the result value as a double"); } final Object result = buildMeasureResult(version, dValue, uom, rid); observations.add(OMXmlFactory.buildMeasurement(version, obsID, name, null, prop, phen, procedure, result, time)); } } } } } return observations; } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage(), ex); } catch (DataStoreException ex) { throw new DataStoreException("the service has throw a Datastore Exception:" + ex.getMessage(), ex); } } private Object buildMeasureResult(final String version, final double value, final String uom, final String resultId) { final String name = "measure-00" + resultId; return buildMeasure(version, name, uom, value); } @Override public String getResults() throws DataStoreException { try { // add orderby to the query final Field timeField = getTimeField(currentProcedure); if (timeField != null) { sqlRequest.append(sqlMeasureRequest.toString().replace("$time", timeField.fieldName)); } sqlRequest.append(" ORDER BY o.\"id\", m.\"id\""); final StringBuilder values = new StringBuilder(); try(final Connection c = source.getConnection()) { try(final Statement currentStatement = c.createStatement()) { LOGGER.info(sqlRequest.toString()); final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString()); final List<Field> fields; if (!currentFields.isEmpty()) { fields = new ArrayList<>(); // we add the main field TODO profiles??? if (timeField != null) { fields.add(timeField); } for (String f : currentFields) { final Field field = getFieldForPhenomenon(currentProcedure, f, c); if (!fields.contains(field)) { fields.add(field); } } } else { fields = readFields(currentProcedure, c); } final TextBlock encoding; if ("text/csv".equals(responseFormat)) { encoding = getCsvTextEncoding("2.0.0"); // Add the header for (Field pheno : fields) { values.append(pheno.fieldName).append(','); } values.setCharAt(values.length() - 1, '\n'); } else { encoding = getDefaultTextEncoding("2.0.0"); } while (rs.next()) { for (int i = 0; i < fields.size(); i++) { Field field = fields.get(i); String value = rs.getString(field.fieldName); // for time TODO remove when field will be typed if (value != null && field.fieldType.equals("Time")) { value = value.replace(' ', 'T'); value = value.substring(0, value.length() - 2); } else if (value == null) { value = ""; } values.append(value).append(encoding.getTokenSeparator()); } values.deleteCharAt(values.length() - 1); values.append(encoding.getBlockSeparator()); } } } return values.toString(); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage(), ex); } } @Override public String getDecimatedResults(final int width) throws DataStoreException { try { // add orderby to the query final String fieldRequest = sqlRequest.toString(); sqlRequest.append(" ORDER BY o.\"id\", m.\"id\""); final StringBuilder values = new StringBuilder(); try(final Connection c = source.getConnection()) { try (final Statement currentStatement = c.createStatement()) { LOGGER.info(sqlRequest.toString()); try (final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString())) { final TextBlock encoding; final List<Field> fields; if (!currentFields.isEmpty()) { fields = new ArrayList<>(); // we add the main field TODO profiles??? final Field timeField = getTimeField(currentProcedure, c); if (timeField != null) { fields.add(timeField); } for (String f : currentFields) { final Field field = getFieldForPhenomenon(currentProcedure, f, c); if (field != null && !fields.contains(field)) { fields.add(field); } } } else { fields = readFields(currentProcedure, c); } if ("text/csv".equals(responseFormat)) { encoding = getCsvTextEncoding("2.0.0"); // Add the header for (Field pheno : fields) { // hack for the current graph in cstl you only work when the main field is named "time" if ("Time".equals(pheno.fieldType)) { values.append("time").append(','); } else { values.append(pheno.fieldName).append(','); } } values.setCharAt(values.length() - 1, '\n'); } else { encoding = getDefaultTextEncoding("2.0.0"); } Map<String, Double> minVal = initMapVal(fields, false); Map<String, Double> maxVal = initMapVal(fields, true); final long[] times = getMainFieldStepForGetResult(fieldRequest, fields.get(0), c, width); final long step = times[1]; long start = times[0]; while (rs.next()) { long currentMainValue = -1; for (int i = 0; i < fields.size(); i++) { Field field = fields.get(i); String value = rs.getString(field.fieldName); if (i == 0) { if (field.fieldType.equals("Time")) { final Timestamp currentTime = Timestamp.valueOf(value); currentMainValue = currentTime.getTime(); } else if (field.fieldType.equals("Quantity")) { if (value != null && !value.isEmpty()) { final Double d = Double.parseDouble(value); currentMainValue = d.longValue(); } } } addToMapVal(minVal, maxVal, field.fieldName, value); } if (currentMainValue != -1 && currentMainValue > (start + step)) { //min if (fields.get(0).fieldType.equals("Time")) { values.append(format.format(new Date(start))); } else if (fields.get(0).fieldType.equals("Quantity")) { values.append(start); } else { throw new DataStoreException("main field other than Time or Quantity are not yet allowed"); } for (Field field : fields) { if (!field.equals(fields.get(0))) { values.append(encoding.getTokenSeparator()); final double minValue = minVal.get(field.fieldName); if (minValue != Double.MAX_VALUE) { values.append(minValue); } } } values.append(encoding.getBlockSeparator()); //max if (fields.get(0).fieldType.equals("Time")) { long maxTime = start + step; values.append(format.format(new Date(maxTime))); } else if (fields.get(0).fieldType.equals("Quantity")) { values.append(start + step); } else { throw new DataStoreException("main field other than Time or Quantity are not yet allowed"); } for (Field field : fields) { if (!field.equals(fields.get(0))) { values.append(encoding.getTokenSeparator()); final double maxValue = maxVal.get(field.fieldName); if (maxValue != -Double.MAX_VALUE) { values.append(maxValue); } } } values.append(encoding.getBlockSeparator()); start = currentMainValue; minVal = initMapVal(fields, false); maxVal = initMapVal(fields, true); } } } } } return values.toString(); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage(), ex); } } private Map<String, Double> initMapVal(final List<Field> fields, final boolean max) { final Map<String, Double> result = new HashMap<>(); final double value; if (max) { value = -Double.MAX_VALUE; } else { value = Double.MAX_VALUE; } for (Field field : fields) { result.put(field.fieldName, value); } return result; } private void addToMapVal(final Map<String, Double> minMap, final Map<String, Double> maxMap, final String field, final String value) { if (value == null || value.isEmpty()) return; final Double minPrevious = minMap.get(field); final Double maxPrevious = maxMap.get(field); try { final Double current = Double.parseDouble(value); if (current > maxPrevious) { maxMap.put(field, current); } if (current < minPrevious) { minMap.put(field, current); } } catch (NumberFormatException ex) { LOGGER.log(Level.FINER, "unable to parse value:{0}", value); } } private long[] getMainFieldStepForGetResult(String request, final Field mainField, final Connection c, final int width) throws SQLException { request = request.replace("SELECT m.*", "SELECT MIN(\"" + mainField.fieldName + "\"), MAX(\"" + mainField.fieldName + "\") "); try(final Statement stmt = c.createStatement(); final ResultSet rs = stmt.executeQuery(request)) { final long[] result = {-1L, -1L}; if (rs.next()) { if (mainField.fieldType.equals("Time")) { final Timestamp minT = rs.getTimestamp(1); final Timestamp maxT = rs.getTimestamp(2); if (minT != null && maxT != null) { final long min = minT.getTime(); final long max = maxT.getTime(); result[0] = min; result[1] = (max - min) / width; } } else if (mainField.fieldType.equals("Quantity")) { final Double minT = rs.getDouble(1); final Double maxT = rs.getDouble(2); if (minT != null && maxT != null) { final long min = minT.longValue(); final long max = maxT.longValue(); result[0] = min; result[1] = (max - min) / width; } } else { throw new SQLException("unable to extract bound from a " + mainField.fieldType + " main field."); } } return result; } } @Override public List<SamplingFeature> getFeatureOfInterests(final String version) throws DataStoreException { try(final Connection c = source.getConnection()) { final List<SamplingFeature> features = new ArrayList<>(); try(final Statement currentStatement = c.createStatement(); final ResultSet rs = currentStatement.executeQuery(sqlRequest.toString())) { while (rs.next()) { final String id = rs.getString("id"); final String name = rs.getString("name"); final String desc = rs.getString("description"); final String sf = rs.getString("sampledfeature"); final int srid = rs.getInt("crs"); final byte[] b = rs.getBytes("shape"); final CoordinateReferenceSystem crs; if (srid != 0) { crs = CRS.decode(SRIDGenerator.toSRS(srid, SRIDGenerator.Version.V1)); } else { crs = defaultCRS; } final Geometry geom; if (b != null) { WKBReader reader = new WKBReader(); geom = reader.read(b); } else { geom = null; } features.add(buildFoi(version, id, name, desc, sf, geom, crs)); } } return features; } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "SQLException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a SQL Exception:" + ex.getMessage(), ex); }catch (FactoryException ex) { LOGGER.log(Level.SEVERE, "FactoryException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a Factory Exception:" + ex.getMessage(), ex); }catch (ParseException ex) { LOGGER.log(Level.SEVERE, "ParseException while executing the query: {0}", sqlRequest.toString()); throw new DataStoreException("the service has throw a Parse Exception:" + ex.getMessage(), ex); } } @Override public String getOutOfBandResults() throws DataStoreException { throw new ObservationStoreException("Out of band response mode has not been implemented yet", NO_APPLICABLE_CODE, RESPONSE_MODE); } @Override public void setResponseFormat(final String responseFormat) { this.responseFormat = responseFormat; } @Override public boolean computeCollectionBound() { return false; } @Override public Envelope getCollectionBoundingShape() { throw new UnsupportedOperationException("Not supported yet."); } }