/** * 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; import static org.n52.sos.util.DateTimeHelper.formatDateTime2IsoString; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.n52.sos.ds.hibernate.entities.AbstractObservation; 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.ogc.om.OmConstants; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.n52.sos.ogc.sos.SosResultEncoding; import org.n52.sos.ogc.sos.SosResultStructure; import org.n52.sos.ogc.swe.SweAbstractDataComponent; import org.n52.sos.ogc.swe.SweDataArray; import org.n52.sos.ogc.swe.SweDataRecord; import org.n52.sos.ogc.swe.SweField; import org.n52.sos.ogc.swe.encoding.SweAbstractEncoding; import org.n52.sos.ogc.swe.encoding.SweTextEncoding; import org.n52.sos.ogc.swe.simpleType.SweAbstractSimpleType; import org.n52.sos.service.Configurator; import org.n52.sos.util.CollectionHelper; import org.n52.sos.util.DateTimeHelper; import com.vividsolutions.jts.io.WKTWriter; /** * @since 4.0.0 * */ public class ResultHandlingHelper { private static final String RESULT_TIME = OmConstants.RESULT_TIME; private static final String PHENOMENON_TIME = OmConstants.PHENOMENON_TIME; /** * Create internal ResultEncoding from String representation * * @param resultEncoding * String representation of ResultEncoding * @return Internal ResultEncoding */ public static SosResultEncoding createSosResultEncoding(final String resultEncoding) { final SosResultEncoding sosResultEncoding = new SosResultEncoding(); sosResultEncoding.setXml(resultEncoding); return sosResultEncoding; } /** * Create internal ResultStructure from String representation * * @param resultStructure * String representation of ResultStructure * @return Internal ResultStructure */ public static SosResultStructure createSosResultStructure(final String resultStructure) { final SosResultStructure sosResultStructure = new SosResultStructure(); sosResultStructure.setXml(resultStructure); return sosResultStructure; } /** * Create result values from observation according to ResultEncoding and * ResultStructure * * @param observations * Observation to create result values from * @param sosResultEncoding * The ResultEncoding * @param sosResultStructure * The ResultStructure * @return Result values String from observation according to ResultEncoding * and ResultStructure * @throws OwsExceptionReport * If creation fails */ public static String createResultValuesFromObservations(final List<AbstractObservation> observations, final SosResultEncoding sosResultEncoding, final SosResultStructure sosResultStructure) throws OwsExceptionReport { final StringBuilder builder = new StringBuilder(); if (CollectionHelper.isNotEmpty(observations)) { final String tokenSeparator = getTokenSeparator(sosResultEncoding.getEncoding()); final String blockSeparator = getBlockSeparator(sosResultEncoding.getEncoding()); final Map<Integer, String> valueOrder = getValueOrderMap(sosResultStructure.getResultStructure()); addElementCount(builder, observations.size(), blockSeparator); for (final AbstractObservation observation : observations) { for (final Integer intger : valueOrder.keySet()) { final String definition = valueOrder.get(intger); if (definition.equals(PHENOMENON_TIME)) { builder.append(getTimeStringForPhenomenonTime(observation.getPhenomenonTimeStart(), observation.getPhenomenonTimeEnd())); } else if (definition.equals(RESULT_TIME)) { builder.append(getTimeStringForResultTime(observation.getResultTime())); } else { builder.append(getValueAsStringForObservedProperty(observation, definition)); } builder.append(tokenSeparator); } builder.delete(builder.lastIndexOf(tokenSeparator), builder.length()); builder.append(blockSeparator); } if (builder.length() > 0) { builder.delete(builder.lastIndexOf(blockSeparator), builder.length()); } } return builder.toString(); } /** * Get token separator from encoding * * @param encoding * Abstract encoding * @return Token separator */ public static String getTokenSeparator(final SweAbstractEncoding encoding) { if (encoding instanceof SweTextEncoding) { return ((SweTextEncoding) encoding).getTokenSeparator(); } return null; } /** * Get block separator from encoding * * @param encoding * Abstract encoding * @return Block separator */ public static String getBlockSeparator(final SweAbstractEncoding encoding) { if (encoding instanceof SweTextEncoding) { return ((SweTextEncoding) encoding).getBlockSeparator(); } return null; } /** * Check if data component has a result time element and return the position * * @param sweDataElement * Data component * @return Position of the result time element or -1 if it is not contained */ public static int hasResultTime(final SweAbstractDataComponent sweDataElement) { if (sweDataElement instanceof SweDataArray && ((SweDataArray) sweDataElement).getElementType() instanceof SweDataRecord) { final SweDataArray dataArray = (SweDataArray) sweDataElement; return checkFields(((SweDataRecord) dataArray.getElementType()).getFields(), RESULT_TIME); } else if (sweDataElement instanceof SweDataRecord) { final SweDataRecord dataRecord = (SweDataRecord) sweDataElement; return checkFields(dataRecord.getFields(), RESULT_TIME); } return -1; } /** * Check if data component has a phenomenon time element and return the * position * * @param sweDataElement * Data component * @return Position of the phenomenon time element or -1 if it is not * contained */ public static int hasPhenomenonTime(final SweAbstractDataComponent sweDataElement) { if (sweDataElement instanceof SweDataArray && ((SweDataArray) sweDataElement).getElementType() instanceof SweDataRecord) { final SweDataArray dataArray = (SweDataArray) sweDataElement; return checkFields(((SweDataRecord) dataArray.getElementType()).getFields(), PHENOMENON_TIME); } else if (sweDataElement instanceof SweDataRecord) { final SweDataRecord dataRecord = (SweDataRecord) sweDataElement; return checkFields(dataRecord.getFields(), PHENOMENON_TIME); } return -1; } /** * Check fields for definition and return the position * * @param fields * Fields list to check * @param definition * Definition to check * @return Position of the element with the definition or -1 if it is not * contained */ public static int checkFields(final List<SweField> fields, final String definition) { int i = 0; for (final SweField f : fields) { final SweAbstractDataComponent element = f.getElement(); if (element instanceof SweAbstractSimpleType) { final SweAbstractSimpleType<?> simpleType = (SweAbstractSimpleType<?>) element; if (simpleType.isSetDefinition() && simpleType.getDefinition().equals(definition)) { return i; } } ++i; } return -1; } private static void addElementCount(final StringBuilder builder, final int size, final String blockSeparator) { builder.append(String.valueOf(size)); builder.append(blockSeparator); } private static Object getTimeStringForResultTime(final Date resultTime) { if (resultTime != null) { return DateTimeHelper.formatDateTime2IsoString(new DateTime(resultTime, DateTimeZone.UTC)); } return Configurator.getInstance().getProfileHandler().getActiveProfile().getResponseNoDataPlaceholder(); } private static Object getTimeStringForPhenomenonTime(final Date phenomenonTimeStart, final Date phenomenonTimeEnd) { if (phenomenonTimeStart == null && phenomenonTimeEnd == null) { return Configurator.getInstance().getProfileHandler().getActiveProfile().getResponseNoDataPlaceholder(); } final StringBuilder builder = new StringBuilder(); if (phenomenonTimeStart.equals(phenomenonTimeEnd)) { builder.append(formatDateTime2IsoString(new DateTime(phenomenonTimeStart, DateTimeZone.UTC))); } else { builder.append(formatDateTime2IsoString(new DateTime(phenomenonTimeStart, DateTimeZone.UTC))); builder.append('/'); builder.append(formatDateTime2IsoString(new DateTime(phenomenonTimeEnd, DateTimeZone.UTC))); } return builder.toString(); } private static Map<Integer, String> getValueOrderMap(final SweAbstractDataComponent sweDataElement) { final Map<Integer, String> valueOrder = new HashMap<Integer, String>(0); if (sweDataElement instanceof SweDataArray && ((SweDataArray) sweDataElement).getElementType() instanceof SweDataRecord) { final SweDataArray dataArray = (SweDataArray) sweDataElement; addOrderAndDefinitionToMap(((SweDataRecord) dataArray.getElementType()).getFields(), valueOrder); } else if (sweDataElement instanceof SweDataRecord) { final SweDataRecord dataRecord = (SweDataRecord) sweDataElement; addOrderAndDefinitionToMap(dataRecord.getFields(), valueOrder); } return new TreeMap<Integer, String>(valueOrder); } private static void addOrderAndDefinitionToMap(final List<SweField> fields, final Map<Integer, String> valueOrder) { for (int i = 0; i < fields.size(); i++) { final SweAbstractDataComponent element = fields.get(i).getElement(); if (element instanceof SweAbstractSimpleType) { final SweAbstractSimpleType<?> simpleType = (SweAbstractSimpleType<?>) element; if (simpleType.isSetDefinition()) { addValueToValueOrderMap(valueOrder, i, simpleType.getDefinition()); } } } } private static void addValueToValueOrderMap(final Map<Integer, String> valueOrder, final int index, final String value) { if (index >= 0) { valueOrder.put(index, value); } } private static String getValueAsStringForObservedProperty(final AbstractObservation observation, final String definition) { final String observedProperty = observation.getObservableProperty().getIdentifier(); if (observedProperty.equals(definition)) { if (observation instanceof NumericObservation) { return String.valueOf(((NumericObservation) observation).getValue()); } else if (observation instanceof BooleanObservation) { return String.valueOf(((BooleanObservation) observation).getValue()); } else if (observation instanceof CategoryObservation) { return String.valueOf(((CategoryObservation) observation).getValue()); } else if (observation instanceof CountObservation) { return String.valueOf(((CountObservation) observation).getValue()); } else if (observation instanceof TextObservation) { return String.valueOf(((TextObservation) observation).getValue()); } else if (observation instanceof GeometryObservation) { final WKTWriter writer = new WKTWriter(); return writer.write(((GeometryObservation) observation).getValue()); } else if (observation instanceof BlobObservation) { return String.valueOf(((BlobObservation) observation).getValue()); } // // TODO multiple values? // Set<BooleanValue> booleanValues = observation.getBooleanValue(); // if (booleanValues != null && !booleanValues.isEmpty()) { // return // String.valueOf(booleanValues.iterator().next().getValue()); // } // // Set<CategoryValue> categoryValues = // observation.getCategoryValue(); // if (categoryValues != null && !categoryValues.isEmpty()) { // return categoryValues.iterator().next().getValue(); // } // // Set<CountValue> countValues = observation.getCountValue(); // if (countValues != null && !countValues.isEmpty()) { // return String.valueOf(countValues.iterator().next().getValue()); // } // // Set<NumericValue> numericValues = observation.getNumericValues(); // if (numericValues != null && !numericValues.isEmpty()) { // return // String.valueOf(numericValues.iterator().next().getValue()); // } // // //TODO geometry values; // // Set<TextValue> textValues = observation.getTextValues(); // if (textValues != null && !textValues.isEmpty()) { // StringBuilder builder = new StringBuilder(); // for (TextValue textValue : textValues) { // builder.append(textValue.getValue()); // } // return builder.toString(); // } } return Configurator.getInstance().getProfileHandler().getActiveProfile().getResponseNoDataPlaceholder(); } private ResultHandlingHelper() { } }