/** * Copyright (C) 2008 - 2014 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 * icense 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.ses.io.parser; import java.math.BigInteger; import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import javax.xml.namespace.QName; import net.opengis.gml.AbstractFeatureCollectionType; import net.opengis.gml.AbstractTimeObjectType; import net.opengis.gml.BoundingShapeType; import net.opengis.gml.EnvelopeType; import net.opengis.gml.FeatureCollectionDocument; import net.opengis.gml.FeatureCollectionDocument2; import net.opengis.gml.FeaturePropertyType; import net.opengis.gml.PointType; import net.opengis.gml.TimeInstantType; import net.opengis.gml.TimePeriodType; import net.opengis.gml.TimePositionType; import net.opengis.om.x10.ObservationDocument; import net.opengis.om.x10.ObservationType; import net.opengis.om.x10.ProcessPropertyType; import net.opengis.sampling.x10.SamplingPointDocument; import net.opengis.sampling.x10.SamplingPointType; import net.opengis.swe.x101.AbstractDataRecordType; import net.opengis.swe.x101.AnyScalarPropertyType; import net.opengis.swe.x101.CompositePhenomenonType; import net.opengis.swe.x101.DataArrayDocument; import net.opengis.swe.x101.DataArrayType; import net.opengis.swe.x101.DataComponentPropertyType; import net.opengis.swe.x101.DataRecordDocument; import net.opengis.swe.x101.DataRecordType; import net.opengis.swe.x101.PhenomenonPropertyType; import net.opengis.swe.x101.PhenomenonType; import net.opengis.swe.x101.SimpleDataRecordType; import net.opengis.swe.x101.TimeObjectPropertyType; import net.opengis.swe.x101.UomPropertyType; import net.opengis.swe.x101.CategoryDocument.Category; import net.opengis.swe.x101.CountDocument.Count; import net.opengis.swe.x101.QuantityDocument.Quantity; import net.opengis.swe.x101.TextBlockDocument.TextBlock; import net.opengis.swe.x101.TextDocument.Text; import net.opengis.swe.x101.TimeDocument.Time; import org.apache.muse.util.xml.XmlUtils; import org.apache.muse.ws.addressing.soap.SoapFault; import org.apache.muse.ws.notification.NotificationMessage; import org.apache.xmlbeans.QNameSet; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; import org.joda.time.DateTime; import org.n52.oxf.conversion.unit.CustomUnitConverter; import org.n52.oxf.conversion.unit.NumberWithUOM; import org.n52.oxf.conversion.unit.UOMTools; import org.n52.oxf.xmlbeans.parser.XMLBeansParser; import org.n52.ses.api.AbstractParser; import org.n52.ses.api.event.MapEvent; import org.n52.ses.util.common.ConfigurationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.WKTReader; /** * Parses OGC O&M documents as events * */ public class OMParser extends AbstractParser { private static final Logger logger = LoggerFactory .getLogger(OMParser.class); /** * the namespace of the used O&M version */ public static final String OM_NAMESPACE = "http://www.opengis.net/om/1.0"; /** * the namespace for O&M 1.0 with GML 3.2 */ public static final String OM_GML32_NAMESPACE = "http://www.opengis.net/om/1.0/gml32"; private static final String PHENOMENON_STRING_KEY = "phenomenon"; private static final String UOM_STRING_KEY = "uom"; private static final String IS_UCUM_BOOLEAN_KEY = "isUcum"; private static final String IS_TIME_BOOLEAN_KEY = "isTime"; private static final String POSITION_INT_KEY = "position"; public OMParser() { UOMTools.addCustomUnitConverter(new CustomUnitConverter() { @Override public String getUnitString() { return "m+NN"; } @Override public String getBaseUnit() { return "m"; } @Override public NumberWithUOM convert(double doubleValue) { return new NumberWithUOM(doubleValue, "m"); } }); } /** * @param oDoc O&M Observation document to be parsed * @return a {@link List} of parsed {@link MapEvent} * @throws Exception exception */ public List<MapEvent> parseOM(ObservationDocument oDoc) throws Exception { //the resulting new events ArrayList<MapEvent> events = new ArrayList<MapEvent>(); ObservationType observation = null; if (oDoc != null) { observation = oDoc.getObservation(); } if (observation == null) throw new SoapFault("No " + "Observation found!"); //the phenomenon/uom list List<Map<String, Object>> pums = new LinkedList<Map<String, Object>>(); boolean hasTimestamp = false; /* * Parse om:result. Use this phenomenons (and timestamps) */ XmlObject result = observation.getResult(); if (result instanceof XmlAnyTypeImpl) { XmlAnyTypeImpl anyTypeDoc = (XmlAnyTypeImpl) result; XmlObject xobj = null; xobj = XMLBeansParser.parse(anyTypeDoc.toString(), false); if (xobj != null && xobj instanceof DataArrayDocument) { /* * parse data array */ parseDataArray((DataArrayDocument) xobj, pums, events); } else { //parse anything else than data arrays //check if content is of Group swe:AnyScalar and try parsing if (!parseAnyScalarTypes(anyTypeDoc, events)){ /* * use swe:DataRecords */ if (!parseDataRecord(xobj, events)) { /* * parse as double or string, was not an AnyScalar type */ parseAsSingleValue(anyTypeDoc, events); } } /* * parsing for OWS-7 * * will use swe:DataRecords */ if (xobj != null && xobj instanceof DataRecordDocument) { //result does not need to be parsed. TODO: why? //one event will be sent per notification so one event has to be created } } } /* * check for a timestamp */ if (events.size() > 0) { Object tempTime = events.get(0).get(MapEvent.START_KEY); if (tempTime != null) { if ((Long) tempTime != 0) { hasTimestamp = true; } } } /* * parse time from samplingTime */ if (!hasTimestamp) { TimeObjectPropertyType topt = observation.getSamplingTime(); AbstractTimeObjectType to = topt.getTimeObject(); if (to instanceof TimeInstantType) { TimeInstantType tit = (TimeInstantType) to; TimePositionType tp = tit.getTimePosition(); long timeStamp = getTimestamp(tp.getStringValue(), null); //put time for (MapEvent me : events) { me.put(MapEvent.START_KEY, timeStamp); me.put(MapEvent.END_KEY, timeStamp); } } else if (to instanceof TimePeriodType) { TimePeriodType tpt = (TimePeriodType) to; TimePositionType bp = tpt.getBeginPosition(); TimePositionType ep = tpt.getEndPosition(); long begin = getTimestamp(bp.getStringValue(), null); long end = getTimestamp(ep.getStringValue(), null); //put time for (MapEvent me : events) { me.put(MapEvent.START_KEY, begin); me.put(MapEvent.END_KEY, end); } } } /* * parse the sensor-id from procedure */ ProcessPropertyType proc = observation.getProcedure(); String sensorId = ""; if (proc.isSetHref()) { sensorId = proc.getHref(); } /* * put sensor-id and procedure */ for (MapEvent me : events) { me.put(MapEvent.SENSORID_KEY, sensorId); me.put("procedure", sensorId); // // if (observation.getProcedure().isSetHref()) { // me.put("procedure", observation.getProcedure().getHref()); // } } /* * parse observed property */ PhenomenonPropertyType observedProperty = observation.getObservedProperty(); if (observedProperty.isSetHref()) { OMParser.logger.debug("########################## parsing observed property"); String obProp = observedProperty.getHref(); //put observed property for (MapEvent me : events) { me.put(MapEvent.OBSERVED_PROPERTY_KEY, obProp); } } else { /* * Special treatment of observations from pegel-online SOS * holding composite phenomena * BAW_MODE is required */ OMParser.logger.debug("#############################\n\n"); ConfigurationRegistry config = ConfigurationRegistry.getInstance(); boolean bawMode = false; Object gm = config.getPropertyForKey(ConfigurationRegistry.USE_FOR_BAW); if (gm != null) { bawMode = Boolean.parseBoolean(gm.toString()); } if(bawMode){ OMParser.logger.debug("BAW is ON"); PhenomenonType phen = observedProperty.getPhenomenon(); if (phen instanceof CompositePhenomenonType) { OMParser.logger.debug("found composite phenomenon"); CompositePhenomenonType compPhen = (CompositePhenomenonType) phen; int length = compPhen.getComponentArray().length; PhenomenonPropertyType comp = compPhen.getComponentArray(length-1); if(comp.isSetHref()){ String obProp = comp.getHref(); OMParser.logger.debug("using last component of composite phenomenon with href:\"" + obProp + "\""); //put observed property for (MapEvent me : events) { me.put(MapEvent.OBSERVED_PROPERTY_KEY, obProp); } } } } else { OMParser.logger.debug("BAW is OFF"); } } /* * parse featureOfInterest -> Geometry */ FeaturePropertyType foi = observation.getFeatureOfInterest(); XmlObject feature = XmlObject.Factory.parse(foi.toString()); parseFeature(feature, events); return events; } private void parseFeature(XmlObject feature, List<MapEvent> events) throws com.vividsolutions.jts.io.ParseException, XmlException { Geometry geom = null; String foiID = ""; if (feature instanceof FeatureCollectionDocument2 || feature instanceof FeatureCollectionDocument) { AbstractFeatureCollectionType fct; if (feature instanceof FeatureCollectionDocument2) { fct = ((FeatureCollectionDocument2) feature).getFeatureCollection(); } else { fct = ((FeatureCollectionDocument) feature).getFeatureCollection(); } FeaturePropertyType[] fmarray = fct.getFeatureMemberArray(); for (FeaturePropertyType fpt : fmarray) { XmlObject member = XmlObject.Factory.parse(fpt.toString()); /* * recursive call */ parseFeature(member, events); return; } } /* * no feature collection */ else if (feature instanceof SamplingPointDocument) { SamplingPointType spt = ((SamplingPointDocument) feature).getSamplingPoint(); geom = getPositionFromSamplingPoint(spt); if (spt.isSetId()) { foiID = spt.getId(); } } /* * put geometry */ if (geom != null) { for (MapEvent me : events) { me.put(MapEvent.GEOMETRY_KEY, geom); } } /* * put foi id */ if (!foiID.equals("")) { for (MapEvent me : events) { me.put(MapEvent.FOI_ID_KEY, foiID); } } } private boolean parseDataRecord(XmlObject xobj, ArrayList<MapEvent> events) { DataRecordType dr = null; if (xobj instanceof DataRecordDocument) { dr = ((DataRecordDocument) xobj).getDataRecord(); } else if (xobj instanceof DataRecordType) { dr = (DataRecordType) xobj; } if (dr != null) { DataComponentPropertyType[] fields = dr.getFieldArray(); /* * new event with dummy time, later changed */ MapEvent newEvent = new MapEvent(0, 0); for (DataComponentPropertyType field : fields) { if (field.isSetTime()) { /* * change the timestamp */ Time time = field.getTime(); DateTime dateTime = new DateTime(time.getValue()); newEvent.put(MapEvent.START_KEY, dateTime.getMillis()); newEvent.put(MapEvent.END_KEY, dateTime.getMillis()); } else if (field.isSetQuantity()) { /* * parse quantity */ Quantity quan = field.getQuantity(); double value = quan.getValue(); String name = field.getName(); if (quan.isSetUom()) { if (quan.getUom().isSetCode()) { NumberWithUOM temp = this.unitConverter.convert(quan.getUom().getCode(), value); newEvent.put(name, temp.getValue()); } else newEvent.put(name, value); } else newEvent.put(name, value); } else if (field.isSetCount()) { /* * parse count */ } } events.add(newEvent); /* * we succeeded */ return true; } /* * we failed */ return false; } /** * Parses a DataArray inside the om:result * * @param dad the {@link DataArrayDocument} * @param pums List of phenomenon/uom models * @param events new Events are added to this list * @throws Exception */ private void parseDataArray(DataArrayDocument dad, List<Map<String, Object>> pums, ArrayList<MapEvent> events) throws Exception { //TODO: add parsing of doubleValue and stringValue DataArrayType array = dad.getDataArray1(); BigInteger elemCount = array.getElementCount().getCount().getValue(); //get the type DataComponentPropertyType elemType = array.getElementType(); /* * Build event structure. */ if (elemType.isSetAbstractDataRecord()) { AbstractDataRecordType adr = elemType.getAbstractDataRecord(); //SimpleDataRecord if (adr instanceof SimpleDataRecordType) { SimpleDataRecordType sdr = (SimpleDataRecordType) adr; Map<String, Object> pum; for (int i = 0; i < sdr.getFieldArray().length; i++) { pum = getPhenomenonAndUomFromScalar(sdr.getFieldArray(i)); pum.put(POSITION_INT_KEY, i); pums.add(pum); } } else if (adr instanceof DataRecordType) { DataRecordType sdr = (DataRecordType) adr; for (int i = 0; i < sdr.getFieldArray().length; i++) { Map<String, Object> pum = getPhenomenonAndUomFromComponent(sdr.getFieldArray(i)); pum.put(POSITION_INT_KEY, i); pums.add(pum); } } } /* * Fill MapEvent with data. */ final TextBlock textblock = array.getEncoding().getTextBlock(); final String blockS = textblock.getBlockSeparator(); final String tokenS = textblock.getTokenSeparator(); final String decimalS = textblock.getDecimalSeparator(); Element elem = (Element) array.getValues().getDomNode(); String values = XmlUtils.toString(elem.getFirstChild()).trim(); StringTokenizer line = new StringTokenizer(values, blockS); String current = null; MapEvent newEvent; StringTokenizer fields; boolean firstQuantity; Object finalValue = null; int count = 0; int i = 0; while (line.hasMoreTokens()) { i = 0; newEvent = new MapEvent(0, 0); firstQuantity = true; current = line.nextToken(); fields = new StringTokenizer(current, tokenS); while (fields.hasMoreTokens()) { Map<String, Object> pum = pums.get(i); if (i != ((Integer) pum.get(POSITION_INT_KEY)) ) { OMParser.logger.warn("Probably using wrong phenomenon for values! Recheck code."); } current = fields.nextToken(); if ((Boolean) pum.get(IS_UCUM_BOOLEAN_KEY)) { //got value for conversion current.replaceAll(decimalS, "."); Double value = Double.NaN; try { value = Double.parseDouble(current); } catch (NumberFormatException e) { OMParser.logger.warn(e.getMessage(), e); } if (value != Double.NaN) { // Object[] conv = this.converter.convert((String) pum.get(UOM_STRING_KEY), // (String) pum.get(PHENOMENON_STRING_KEY), value); //no usage of registered phenomena as their registration seems not to work (and is also not intended / needed) String uom = (String) pum.get(UOM_STRING_KEY); double converted = UOMTools.convertToBaseUnit(value, uom); newEvent.put((String) pum.get(PHENOMENON_STRING_KEY), converted); if (firstQuantity) { //it is the first quantity, set as final value finalValue = converted; firstQuantity = false; } } // else { // newEvent.put((String) pum.get(PHENOMENON_STRING_KEY), value); // } // no else!! would result in Double.NaN in the event. } else if ((Boolean) pum.get(IS_TIME_BOOLEAN_KEY)) { long timeStamp = getTimestamp(current, pum); newEvent.put(MapEvent.START_KEY, timeStamp); newEvent.put(MapEvent.END_KEY, timeStamp); } else { newEvent.put((String) pum.get(PHENOMENON_STRING_KEY), current); if (finalValue != null) { //final value has not yet been set, use this one finalValue = current; } } i++; } //set the value field if (finalValue != null) { newEvent.put(MapEvent.VALUE_KEY, finalValue); } events.add(newEvent); count++; } if (count != elemCount.intValue()) { OMParser.logger.info("Unexpected element count: expected "+ elemCount +", got "+ count +"."); } } /** * Process and parse any type of swe:AnyScalar inside the om:result * * @param omResultContent the anyScalar element * @param events resulting events are added to this list * @return true if an AnyScalar type was found and parsed. */ private boolean parseAnyScalarTypes(XmlObject omResultContent, ArrayList<MapEvent> events) { if (omResultContent == null) return false; /* * select children that are of AnyScalar group */ String sweNS = "http://www.opengis.net/swe/1.0.1"; QName[] qnArray = new QName[] { new QName(sweNS, "Count"), new QName(sweNS, "Quantity"), new QName(sweNS, "Time"), new QName(sweNS, "Boolean"), new QName(sweNS, "Category"), new QName(sweNS, "Text") }; QNameSet qns = QNameSet.forArray(qnArray); qnArray = null; XmlObject[] anyScalars = omResultContent.selectChildren(qns); /* * if found any, parse the results */ if (anyScalars.length > 0) { for (XmlObject as : anyScalars) { UomPropertyType uom = null; double doubleValue = Double.NaN; String stringValue = null; String definition = null; /* * AnyNumerical */ if (as instanceof Count) { Count count = (Count) as; if (count.isSetValue()) { doubleValue = Double.parseDouble(""+ count.getValue()); } if (count.isSetDefinition()) { definition = count.getDefinition(); } } else if (as instanceof Quantity) { Quantity quant = (Quantity) as; if (quant.isSetUom()) { uom = quant.getUom(); } if (quant.isSetValue()) { doubleValue = quant.getValue(); } if (quant.isSetDefinition()) { definition = quant.getDefinition(); } } else if (as instanceof Time) { //TODO parse } /* * Other AnyScalars */ else if (as instanceof net.opengis.swe.x101.BooleanDocument.Boolean) { net.opengis.swe.x101.BooleanDocument.Boolean bool = (net.opengis.swe.x101.BooleanDocument.Boolean) as; if (bool.isSetValue()) { stringValue = ""+ bool.getValue(); } if (bool.isSetDefinition()) { definition = bool.getDefinition(); } } else if (as instanceof Category) { Category cat = (Category) as; if (cat.isSetValue()) { stringValue = cat.getValue(); } if (cat.isSetDefinition()) { definition = cat.getDefinition(); } } else if (as instanceof Text) { Text text = (Text) as; if (text.isSetValue()) { stringValue = text.getValue(); } if (text.isSetDefinition()) { definition = text.getDefinition(); } } //convert if a uom was found if (uom != null && doubleValue != Double.NaN) { try { //convert doubleValue = (Double) this.unitConverter.convert(uom.getCode(), doubleValue).getValue(); } catch (Throwable t) { OMParser.logger.info("could not convert uom '" + uom + "' to base unit, reason: " + t.getMessage()); } } /* * generate new event */ MapEvent newEvent = new MapEvent(0, 0); if (doubleValue != Double.NaN) { newEvent.put(MapEvent.VALUE_KEY, doubleValue); newEvent.put(MapEvent.RESULT_KEY, doubleValue); //add to new event with definition (observed property) if (definition != null) { newEvent.put(definition.replaceAll(":", "__").replaceAll("\\.", "_"), doubleValue); } } else if (stringValue != null) { newEvent.put(MapEvent.STRING_VALUE_KEY, stringValue); newEvent.put(MapEvent.RESULT_KEY, stringValue); //add to new event with definition (observed property) if (definition != null) { newEvent.put(definition.replaceAll(":", "__").replaceAll("\\.", "_"), stringValue); } } events.add(newEvent); } } else { return false; } return true; } /** * Nothing else worked. Parse as a single double or string value in the om:result here. * @param anyTypeDoc the xml-fragement. * @param events resulting events are added to this list. */ private void parseAsSingleValue(XmlAnyTypeImpl anyTypeDoc, ArrayList<MapEvent> events) { double value = Double.NaN; boolean isDouble = true; try { String s = anyTypeDoc.getStringValue().trim(); value = Double.parseDouble(s); } catch (Exception ex) { //not a double? contine isDouble = false; } if (isDouble) { //result is a double value MapEvent newEvent = new MapEvent(0, 0); String uom = ""; int attributeLenght = anyTypeDoc.getDomNode().getAttributes().getLength(); String localName; //try to find a uom attribute for (int i = 0; i < attributeLenght; i++) { localName = anyTypeDoc.getDomNode().getAttributes().item(i).getLocalName(); if (localName.equals("uom")) { uom = anyTypeDoc.getDomNode().getAttributes().item(i).getNodeValue(); } } //if uom was found, convert the value if (!uom.equals("")) { try { //convert value = (Double) this.unitConverter.convert(uom, value).getValue(); } catch (Throwable t) { OMParser.logger.info("could not convert uom '" + uom + "' to base unit, reason: " + t.getMessage()); } } newEvent.put(MapEvent.VALUE_KEY, value); newEvent.put(MapEvent.RESULT_KEY, value); newEvent.put(MapEvent.DOUBLE_VALUE_KEY, value); newEvent.put(MapEvent.STRING_VALUE_KEY, "" + value); events.add(newEvent); } else { //parse as a simple string, nothing else worked MapEvent newEvent = new MapEvent(0, 0); String textValue = anyTypeDoc.getStringValue().trim(); newEvent.put(MapEvent.VALUE_KEY, textValue); newEvent.put(MapEvent.RESULT_KEY, textValue); newEvent.put(MapEvent.STRING_VALUE_KEY, textValue); events.add(newEvent); } } /** * Parse the position from a given {@link SamplingPointType} */ private Geometry getPositionFromSamplingPoint(SamplingPointType spt) throws com.vividsolutions.jts.io.ParseException { if (spt.getPosition().isSetPoint()) { PointType point = spt.getPosition().getPoint(); if (point.isSetPos()) { WKTReader reader = new WKTReader(); return reader.read("POINT("+ point.getPos().getStringValue() + ")"); } } else if (spt.isSetBoundedBy()) { BoundingShapeType bb = spt.getBoundedBy(); EnvelopeType env = bb.getEnvelope(); return getGeometryFromEnvelope(env); } return null; } /** * Parse the position from a given {@link EnvelopeType} */ private Geometry getGeometryFromEnvelope(EnvelopeType et) throws com.vividsolutions.jts.io.ParseException { Element elem = (Element) et.getUpperCorner().getDomNode(); String ucString = XmlUtils.toString(elem.getFirstChild()).trim(); String[] uc = ucString.split(" "); int i = 0; for (String string : uc) { string = string.trim(); uc[i] = string; i++; } //get lower corner and split at " " elem = (Element) et.getLowerCorner().getDomNode(); String lcString = XmlUtils.toString(elem.getFirstChild()).trim(); String[] lc = lcString.split(" "); i = 0; for (String string : lc) { string = string.trim(); lc[i] = string; i++; } String wktString = "POLYGON(("+ lc[0] +" "+ lc[1] +", "+ lc[0] +" "+ uc[1] +", "+ uc[0] +" "+ uc[1] + ", "+ uc[0] +" "+ lc[1] +", "+ lc[0] +" "+ lc[1]+ "))"; WKTReader wktReader = new WKTReader(); return wktReader.read(wktString); } /** * Parse the phenomenon and UOM from an {@link AnyScalarPropertyType} */ private Map<String, Object> getPhenomenonAndUomFromScalar(AnyScalarPropertyType scalar) throws Exception { Map<String, Object> result = new HashMap<String, Object>(); result.put(IS_TIME_BOOLEAN_KEY, false); result.put(IS_UCUM_BOOLEAN_KEY, false); result.put(POSITION_INT_KEY, -1); String phen; String uom; if (scalar.isSetBoolean()) { phen = scalar.getBoolean().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = ""; } else if (scalar.isSetQuantity()) { phen = scalar.getQuantity().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = getUom(scalar.getQuantity().getUom(), result); } else if (scalar.isSetCount()) { phen = scalar.getCount().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = ""; } else if (scalar.isSetTime()) { phen = scalar.getTime().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = getUom(scalar.getTime().getUom(), result); result.put(IS_TIME_BOOLEAN_KEY, true); } else if (scalar.isSetText()) { uom = ""; phen = scalar.getText().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); } else if(scalar.isSetCategory()) { uom = ""; phen = scalar.getCategory().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); } else { return null; } result.put(PHENOMENON_STRING_KEY, phen); result.put(UOM_STRING_KEY, uom); return result; } /** * Parse the phenomenon and UOM from an {@link DataComponentPropertyType} */ private Map<String, Object> getPhenomenonAndUomFromComponent( DataComponentPropertyType component) throws Exception { Map<String, Object> result = new HashMap<String, Object>(); result.put(IS_TIME_BOOLEAN_KEY, false); result.put(IS_UCUM_BOOLEAN_KEY, false); result.put(POSITION_INT_KEY, -1); String phen; String uom; if (component.isSetBoolean()) { phen = component.getBoolean().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = ""; } else if (component.isSetQuantity()) { phen = component.getQuantity().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = getUom(component.getQuantity().getUom(), result); } else if (component.isSetCount()) { phen = component.getCount().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = ""; } else if (component.isSetTime()) { phen = component.getTime().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); uom = getUom(component.getTime().getUom(), result); result.put(IS_TIME_BOOLEAN_KEY, true); } else if (component.isSetText()) { uom = ""; phen = component.getText().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); } else if(component.isSetCategory()) { uom = ""; phen = component.getCategory().getDefinition().replaceAll(":", "__").replaceAll("\\.", "_"); } else { throw new SoapFault("the " + "DataComponentPropertyType is an unsupported type:" + component.getType()); } result.put(PHENOMENON_STRING_KEY, phen); result.put(UOM_STRING_KEY, uom); return result; } /** * Get the uom of a {@link UomPropertyType} */ private String getUom(UomPropertyType uom, Map<String, Object> result) { if (uom != null) { if (uom.isSetHref()) { return uom.getHref(); } else if (uom.isSetCode()) { result.put(IS_UCUM_BOOLEAN_KEY, true); return uom.getCode(); } //TODO implement UnitDefinition } return ""; } /** * parses the time provided * * @param time the time to parse * @param pum uom helper * * @return the time as long * @throws ParseException exception */ private long getTimestamp(String time, Map<String, Object> pum) throws ParseException { if (pum != null && pum.get(UOM_STRING_KEY).equals("")) { //TODO: do something with the pum here... //treat as normal timestamp according ISO8601 DateTime dt = new DateTime(time); return dt.getMillis(); } //try also joda time DateTime dt = new DateTime(time); return dt.getMillis(); } @Override public boolean accept(NotificationMessage message) { QName omQName = new QName(OM_NAMESPACE, "Observation"); Element content = message.getMessageContent(omQName); if (content != null) { return true; } return false; } @Override public List<MapEvent> parse(NotificationMessage message) throws Exception { QName omQName = new QName(OM_NAMESPACE, "Observation"); Element content = message.getMessageContent(omQName); if (content != null) { XmlObject oDoc = XMLBeansParser.parse(content, true); return this.parseOM((ObservationDocument) oDoc); } return null; } @Override protected String getName() { return "OMParser"; } }