/* * 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.metadata.io.mdweb; import org.constellation.generic.database.Automatic; import org.constellation.generic.database.BDD; import org.constellation.metadata.io.CSWMetadataReader; import org.constellation.metadata.io.ElementSetType; import org.constellation.metadata.io.MDWebMetadataReader; import org.constellation.metadata.io.MetadataIoException; import org.constellation.metadata.io.MetadataType; import org.constellation.util.ReflectionUtilities; import org.constellation.util.XpathUtils; import org.geotoolkit.csw.xml.DomainValues; import org.geotoolkit.csw.xml.Settable; import org.geotoolkit.csw.xml.v202.AbstractRecordType; import org.geotoolkit.csw.xml.v202.BriefRecordType; import org.geotoolkit.csw.xml.v202.DomainValuesType; import org.geotoolkit.csw.xml.v202.ListOfValuesType; import org.geotoolkit.csw.xml.v202.RecordType; import org.geotoolkit.csw.xml.v202.SummaryRecordType; import org.geotoolkit.dublincore.xml.v2.elements.SimpleLiteral; import org.geotoolkit.ows.xml.v100.BoundingBoxType; import org.geotoolkit.util.StringUtilities; import org.mdweb.io.MD_IOException; import org.mdweb.io.sql.LocalThesaurusHandler; import org.mdweb.io.sql.ThesaurusDatabase; import org.mdweb.model.schemas.CodeListElement; import org.mdweb.model.schemas.Standard; import org.mdweb.model.storage.FullRecord; import org.mdweb.model.storage.TextValue; import org.mdweb.model.storage.Value; import org.mdweb.model.thesaurus.Thesaurus; import org.mdweb.model.thesaurus.Word; import org.w3c.dom.Node; import javax.sql.DataSource; import javax.xml.namespace.QName; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.logging.Level; import static org.constellation.metadata.CSWQueryable.*; import static org.geotoolkit.csw.xml.TypeNames.*; import static org.geotoolkit.ows.xml.OWSExceptionCode.*; /** * A CSW Metadata reader specific for MDweb data source. * It allows to read metadata from the dataSource. * * @author Guilhem Legal (Geomatys) */ public class MDWebCSWMetadataReader extends MDWebMetadataReader implements CSWMetadataReader { /** * A map of binding term-path for each standard. */ protected static final Map<Standard, Map<String, String>> DUBLINCORE_PATH_MAP = new HashMap<>(); static { final Map<String, String> isoMap = new HashMap<>(); isoMap.put("identifier", "ISO 19115:MD_Metadata:fileIdentifier"); isoMap.put("type", "ISO 19115:MD_Metadata:hierarchyLevel"); isoMap.put("date", "ISO 19115:MD_Metadata:dateStamp"); isoMap.put("subject", "ISO 19115:MD_Metadata:identificationInfo:descriptiveKeywords:keyword"); isoMap.put("subject2", "ISO 19115:MD_Metadata:identificationInfo:topicCategory"); isoMap.put("subject3", "ISO 19115:MD_Metadata:identificationInfo:descriptiveKeywords:keyword:value"); isoMap.put("format", "ISO 19115:MD_Metadata:distributionInfo:distributionFormat:name"); isoMap.put("format2", "ISO 19115:MD_Metadata:distributionInfo:distributionFormat:name:value"); isoMap.put("abstract", "ISO 19115:MD_Metadata:identificationInfo:abstract"); isoMap.put("boundingBox", "ISO 19115:MD_Metadata:identificationInfo:extent:geographicElement2"); isoMap.put("creator", "ISO 19115:MD_Metadata:identificationInfo:credit"); isoMap.put("publisher", "ISO 19115:MD_Metadata:distributionInfo:distributor:distributorContact:organisationName"); isoMap.put("language", "ISO 19115:MD_Metadata:language"); isoMap.put("rights", "ISO 19115:MD_Metadata:identificationInfo:resourceConstraint:useLimitation"); isoMap.put("description", "ISO 19115:MD_Metadata:identificationInfo:graphicOverview:fileName"); DUBLINCORE_PATH_MAP.put(Standard.ISO_19115, isoMap); final Map<String, String> iso2Map = new HashMap<>(); iso2Map.put("identifier", "ISO 19115-2:MI_Metadata:fileIdentifier"); iso2Map.put("type", "ISO 19115-2:MI_Metadata:hierarchyLevel"); iso2Map.put("date", "ISO 19115-2:MI_Metadata:dateStamp"); iso2Map.put("subject", "ISO 19115-2:MI_Metadata:identificationInfo:descriptiveKeywords:keyword"); iso2Map.put("subject2", "ISO 19115-2:MI_Metadata:identificationInfo:topicCategory"); iso2Map.put("subject3", "ISO 19115-2:MI_Metadata:identificationInfo:descriptiveKeywords:keyword:value"); iso2Map.put("format", "ISO 19115-2:MI_Metadata:distributionInfo:distributionFormat:name"); iso2Map.put("format2", "ISO 19115-2:MI_Metadata:distributionInfo:distributionFormat:name:value"); iso2Map.put("abstract", "ISO 19115-2:MI_Metadata:identificationInfo:abstract"); iso2Map.put("boundingBox", "ISO 19115-2:MI_Metadata:identificationInfo:extent:geographicElement2"); iso2Map.put("creator", "ISO 19115-2:MI_Metadata:identificationInfo:credit"); iso2Map.put("publisher", "ISO 19115-2:MI_Metadata:distributionInfo:distributor:distributorContact:organisationName"); iso2Map.put("language", "ISO 19115-2:MI_Metadata:language"); iso2Map.put("rights", "ISO 19115-2:MI_Metadata:identificationInfo:resourceConstraint:useLimitation"); iso2Map.put("description", "ISO 19115-2:MI_Metadata:identificationInfo:graphicOverview:fileName"); DUBLINCORE_PATH_MAP.put(Standard.ISO_19115_2, iso2Map); final Map<String, String> ebrimMap = new HashMap<>(); ebrimMap.put("identifier", "Ebrim v3.0:RegistryObject:id"); ebrimMap.put("type", "Ebrim v3.0:RegistryObject:objectType"); ebrimMap.put("abstract", "Ebrim v3.0:RegistryObject:description:localizedString:value"); ebrimMap.put("format", "Ebrim v3.0:ExtrinsicObject:mimeType"); ebrimMap.put("subject", "Ebrim v3.0:RegistryObject:slot:valueList:value"); ebrimMap.put("boudingBox", "Ebrim v3.0:RegistryObject:slot:valueList:value"); /*TODO @name = “http://purl.org/dc/elements/1.1/subject” TODO @slotType =“*:GM_Envelope” ebrimMap.put("creator", "Ebrim v3:RegistryObject:identificationInfo:credit"); ebrimMap.put("publisher", "Ebrim v3:RegistryObject:distributionInfo:distributor:distributorContact:organisationName"); ebrimMap.put("language", "Ebrim v3:RegistryObject:language"); TODO find ebrimMap.put("date", "Ebrim V3:RegistryObject:dateStamp"); */ DUBLINCORE_PATH_MAP.put(Standard.EBRIM_V3, ebrimMap); } /** * A map of label - concept URI loaded from a Thesaurus. * They are used to make Anchor mark in the xml export. */ private final Map<String, URI> conceptMap = new HashMap<>(); public MDWebCSWMetadataReader(final Automatic configuration) throws MetadataIoException { super(configuration); final List<BDD> thesaurusDBs = configuration.getThesaurus(); final List<Thesaurus> thesaurusList = new ArrayList<>(); for (BDD thesaurusDB : thesaurusDBs) { final DataSource source = thesaurusDB.getPooledDataSource(); final String schema = thesaurusDB.getSchema(); final boolean derby = !thesaurusDB.isPostgres(); final ThesaurusDatabase th = new ThesaurusDatabase(source, schema, derby); thesaurusList.add(th); } if (thesaurusList.size() > 0) { final LocalThesaurusHandler tReader = new LocalThesaurusHandler(thesaurusList); final List<Word> words = tReader.getWords(null, true); tReader.close(); for (final Word word : words) { try { final URI uri = new URI(word.getUriConcept()); conceptMap.put(word.getLabel(), uri); } catch (URISyntaxException ex) { LOGGER.log(Level.WARNING, "URI syntax exception for:{0}", word.getUriConcept()); } } } } @Override public List<DomainValues> getFieldDomainofValues(final String propertyNames) throws MetadataIoException { final List<DomainValues> responseList = new ArrayList<>(); final StringTokenizer tokens = new StringTokenizer(propertyNames, ","); while (tokens.hasMoreTokens()) { final String token = tokens.nextToken().trim(); List<String> paths = null; if (ISO_QUERYABLE.get(token) != null) { paths = ISO_QUERYABLE.get(token); } if (paths == null && DUBLIN_CORE_QUERYABLE.get(token) != null) { paths = DUBLIN_CORE_QUERYABLE.get(token); } if (paths == null && INSPIRE_QUERYABLE.get(token) != null) { paths = INSPIRE_QUERYABLE.get(token); } if (paths == null) { throw new MetadataIoException("The property " + token + " is not queryable", INVALID_PARAMETER_VALUE, "propertyName"); } if (!paths.isEmpty()) { paths = XpathUtils.xpathToMDPath(paths); try { final List<String> values = mdReader.getDomainOfValuesFromPaths(paths, true); final ListOfValuesType listValues = new ListOfValuesType(values); final DomainValuesType value = new DomainValuesType(null, token, listValues, METADATA_QNAME); responseList.add(value); } catch (MD_IOException e) { throw new MetadataIoException(e, NO_APPLICABLE_CODE); } } else { throw new MetadataIoException("The property " + token + " is not queryable for now", INVALID_PARAMETER_VALUE, "propertyName"); } } return responseList; } /** * Return a metadata object from the specified identifier. * if is not already in cache it read it from the MDWeb database. * * @param identifier The metadata identifier. * @param mode An output schema mode: EBRIM, ISO_19115 and DUBLINCORE supported. * @param type An elementSet: FULL, SUMMARY and BRIEF. (implies elementName == null) * @param elementName A list of QName describing the requested fields. (implies type == null) * @return A metadata Object (Dublin core Record / GeotoolKit metadata / EBrim registry object) * * @throws MetadataIoException */ @Override public Node getMetadata(final String identifier, final MetadataType mode, final ElementSetType type, final List<QName> elementName) throws MetadataIoException { try { alreadyRead.clear(); //we look for cached object Object result = getFromCache(identifier); if (mode == MetadataType.ISO_19115 || mode == MetadataType.EBRIM || mode == MetadataType.SENSORML || mode == MetadataType.ISO_19110) { if (result == null) { final FullRecord f = mdReader.getRecord(identifier); result = getObjectFromRecord(identifier, f, mode); } else { LOGGER.log(Level.FINER, "getting from cache: {0}", identifier); } result = applyElementSet(result, type, elementName); } else if (mode == MetadataType.DUBLINCORE) { final FullRecord record = mdReader.getRecord(identifier); if (record != null) { final Value top = record.getRoot(); final Standard recordStandard = top.getType().getStandard(); /* * if the standard of the record is CSW and the record is cached we return it. * if the record is not yet cached we proccess. * if the record have to be transform from the orginal standard to CSW we process. */ if (!recordStandard.equals(Standard.CSW) || result == null) { try { result = getRecordFromMDRecord(identifier, record, type, elementName); } catch (IllegalArgumentException ex) { LOGGER.warning(ex.getMessage()); // the metadata is not convertible to DublinCore return null; } } result = applyElementSet(result, type, elementName); } else { throw new MetadataIoException("Unable to read the record: " + identifier, NO_APPLICABLE_CODE, "id"); } } else { throw new IllegalArgumentException("Unknow standard mode: " + mode); } // marshall to DOM if (result != null) { return writeObjectInNode(result, mode); } return null; } catch (MD_IOException e) { throw new MetadataIoException("SQL exception while reading the metadata: " + identifier, e, NO_APPLICABLE_CODE, "id"); } } private Object applyElementSet(final Object result, ElementSetType type, final List<QName> elementName) { if (type == null) { type = ElementSetType.FULL; } // then we apply the elementSet/elementName filter // for an ElementSetName mode if (elementName == null || elementName.isEmpty()) { //if the result can't be filtered by Set filter we return it. if (!(result instanceof Settable)) { return result; } // for a element set FULL we return the record directly if (type == null || type.equals(ElementSetType.FULL)) { return result; // Summary view } else if (type.equals(ElementSetType.SUMMARY)) { return ((Settable) result).toSummary(); // Brief view } else if (type.equals(ElementSetType.BRIEF)) { return ((Settable) result).toBrief(); // this case must never happen } else { return null; } // for an element name mode } else { final Class recordClass = result.getClass(); final Object filtredResult = ReflectionUtilities.newInstance(recordClass); for (final QName qn : elementName) { String currentMethodType = ""; try { currentMethodType = "get"; final Method getter = ReflectionUtilities.getGetterFromName(qn.getLocalPart(), recordClass); final Object param = ReflectionUtilities.invokeMethod(result, getter); if (param != null) { currentMethodType = "set"; Class paramClass = param.getClass(); if (paramClass.equals(ArrayList.class)) { paramClass = List.class; } final Method setter = ReflectionUtilities.getSetterFromName(qn.getLocalPart(), paramClass, recordClass); if (setter != null) { ReflectionUtilities.invokeMethod(setter, filtredResult, param); } else { final String paramDesc = param.getClass().getName(); LOGGER.warning("No setter have been found for attribute " + qn.getLocalPart() +" of type " + paramDesc + " in the class " + recordClass); } } } catch (IllegalArgumentException ex) { LOGGER.severe("illegal argument exception while invoking the method " + currentMethodType + StringUtilities.firstToUpper(qn.getLocalPart()) + " in the classe RecordType!"); } } return filtredResult; } } /** * Return a dublinCore record from a MDWeb record. * * @param record the MDWeb record. * @return a CSW object representing the metadata. */ private AbstractRecordType getRecordFromMDRecord(final String identifier, final FullRecord record, final ElementSetType type, final List<QName> elementName) throws MD_IOException { final Value top = record.getRoot(); final Standard recordStandard = top.getType().getStandard(); if (recordStandard.equals(Standard.ISO_19115) || recordStandard.equals(Standard.ISO_19115_2) || recordStandard.equals(Standard.ISO_19115_FRA) || recordStandard.equals(Standard.EBRIM_V3)) { return transformMDRecordInRecord(record, type, elementName); } else { final Object obj = getObjectFromRecord(identifier, record, MetadataType.DUBLINCORE); if (obj instanceof AbstractRecordType) { return (AbstractRecordType) obj; } else { String objType = "null"; if (obj != null) { objType = obj.getClass().getName(); } throw new IllegalArgumentException("Unexpected type in getRecordFromMDRecord. waiting for AbstractRecordType, got: " + objType); } } } /** * Return a dublinCore record from a ISO 19115 MDWeb record * * @Todo (improvement) return Brief, Summary record before getting all the property. * * @param record the MDWeb record. * @return a CSW object representing the metadata. */ private AbstractRecordType transformMDRecordInRecord(final FullRecord record, final ElementSetType type, final List<QName> elementName) throws MD_IOException { final Value top = record.getRoot(); final Standard recordStandard = top.getType().getStandard(); final Map<String, String> pathMap = DUBLINCORE_PATH_MAP.get(recordStandard); if (pathMap == null) { LOGGER.log(Level.WARNING, "No dublin core path_mapping for standard:{0}", recordStandard.getName()); return null; } // we get the title of the record final SimpleLiteral title = new SimpleLiteral(null, record.getTitle()); // we get the file identifier(s) final List<Value> identifierValues = record.getValueFromPath(pathMap.get("identifier")); final List<String> identifiers = new ArrayList<>(); for (Value v: identifierValues) { if (v instanceof TextValue) { identifiers.add(((TextValue)v).getValue()); } } final SimpleLiteral identifier = new SimpleLiteral(null, identifiers); //we get The boundingBox(es) final List<Value> bboxValues = record.getValueFromPath(pathMap.get("boundingBox")); final List<BoundingBoxType> bboxes = new ArrayList<>(); for (Value v: bboxValues) { bboxes.add(createBoundingBoxFromValue(v.getIdValue(), record, recordStandard)); } //we get the type of the data final List<Value> typeValues = record.getValueFromPath(pathMap.get("type")); String dataType = null; SimpleLiteral litType = null; try { if (!typeValues.isEmpty()) { final TextValue value = (TextValue)typeValues.get(0); final String stringValue = value.getValue(); if (stringValue != null && !stringValue.isEmpty()) { final int code = Integer.parseInt(stringValue); final org.mdweb.model.schemas.CodeList codelist = (org.mdweb.model.schemas.CodeList)value.getType(); final CodeListElement element = codelist.getElementByCode(code); if (element != null) { dataType = element.getName(); } else { LOGGER.warning("No codeListElement found for code:" + code + " in codelist:" + codelist.getName()); } } } litType = new SimpleLiteral(null, dataType); } catch (NumberFormatException ex) { LOGGER.finer("Number format exception while trying to get the DC type using the value as it is in the database"); final TextValue value = (TextValue)typeValues.get(0); final String stringValue = value.getValue(); if (stringValue != null && !stringValue.isEmpty()) { litType = new SimpleLiteral(null, stringValue); } } // we get the keywords final List<Value> keywordsValues = record.getValueFromPath(pathMap.get("subject3")); keywordsValues.addAll(record.getValueFromPath(pathMap.get("subject"))); final List<SimpleLiteral> keywords = new ArrayList<>(); for (Value v: keywordsValues) { if (v instanceof TextValue) { keywords.add(new SimpleLiteral(null, ((TextValue)v).getValue())); } } // we get the topic category final List<Value> topicCategoriesValues = record.getValueFromPath(pathMap.get("subject2")); for (Value v: topicCategoriesValues) { if (v instanceof TextValue) { final String value = ((TextValue)v).getValue(); if (value == null || value.isEmpty()) { continue; } if (v.getType() instanceof org.mdweb.model.schemas.CodeList) { final org.mdweb.model.schemas.CodeList c = (org.mdweb.model.schemas.CodeList) v.getType(); int code = 0; try { code = Integer.parseInt(value); } catch (NumberFormatException ex) { LOGGER.log(Level.WARNING, "unable to parse the codeListelement:{0}", value); } final CodeListElement element = c.getElementByCode(code); if (element != null) { keywords.add(new SimpleLiteral(null, element.getName())); } else { LOGGER.warning("no such codeListElement:" + code + " for the codeList:" + c.getName()); } } else { keywords.add(new SimpleLiteral(null, value)); } } } final List<Value> formatsValues = record.getValueFromPath(pathMap.get("format")); formatsValues.addAll(record.getValueFromPath(pathMap.get("format2"))); final List<String> formats = new ArrayList<>(); for (Value v: formatsValues) { if (v instanceof TextValue) { formats.add(((TextValue)v).getValue()); } } final SimpleLiteral format; if (!formats.isEmpty()) { format = new SimpleLiteral(null, formats); } else { format = null; } final List<Value> dateValues = record.getValueFromPath(pathMap.get("date")); final List<String> dates = new ArrayList<>(); for (Value v: dateValues) { if (v instanceof TextValue) { dates.add(((TextValue)v).getValue()); } } final SimpleLiteral date = new SimpleLiteral(null, dates); // the last update date final SimpleLiteral modified = new SimpleLiteral(null, dates); // the abstracts final List<Value> abstractValues = record.getValueFromPath(pathMap.get("abstract")); final List<String> abstracts = new ArrayList<>(); for (Value v: abstractValues) { if (v instanceof TextValue) { abstracts.add(((TextValue)v).getValue()); } } final SimpleLiteral _abstract = new SimpleLiteral(null, abstracts); // the description final List<Value> descriptionValues = record.getValueFromPath(pathMap.get("description")); final List<SimpleLiteral> descriptions = new ArrayList<>(); for (Value v: descriptionValues) { if (v instanceof TextValue) { descriptions.add(new SimpleLiteral(((TextValue)v).getValue())); } } // TODO add spatial // the creator of the data final List<Value> creatorValues = record.getValueFromPath(pathMap.get("creator")); final List<String> creators = new ArrayList<>(); for (Value v: creatorValues) { if (v instanceof TextValue) { creators.add(((TextValue)v).getValue()); } } final SimpleLiteral creator; if (!creators.isEmpty()) { creator = new SimpleLiteral(null, creators); } else { creator = null; } // the publisher of the data final List<Value> publisherValues = record.getValueFromPath(pathMap.get("publisher")); final List<String> publishers = new ArrayList<>(); for (Value v: publisherValues) { if (v instanceof TextValue) { publishers.add(((TextValue)v).getValue()); } } final SimpleLiteral publisher = new SimpleLiteral(null, publishers); // TODO the contributors // TODO the source of the data // The rights final List<Value> rightValues = record.getValueFromPath(pathMap.get("rights")); final List<String> rights = new ArrayList<>(); for (Value v: rightValues) { if (v instanceof TextValue) { rights.add(((TextValue)v).getValue()); } } final SimpleLiteral right; if (rights.size() > 0) { right = new SimpleLiteral(null, rights); } else { right = null; } // the language final List<Value> languageValues = record.getValueFromPath(pathMap.get("language")); final List<String> languages = new ArrayList<>(); for (Value v: languageValues) { if (v instanceof TextValue) { languages.add(((TextValue)v).getValue()); } } final SimpleLiteral language = new SimpleLiteral(null, languages); final RecordType fullResult = new RecordType(identifier, title, litType , keywords, format, modified, date, _abstract, bboxes, creator, publisher, language, null, null); if (right != null) { fullResult.setRights(right); } if (!descriptions.isEmpty()) { fullResult.setDescription(descriptions); } // for an ElementSetName mode if (elementName == null || elementName.isEmpty()) { if (type.equals(ElementSetType.BRIEF)) { return new BriefRecordType(identifier, title, litType , bboxes); } if (type.equals(ElementSetType.SUMMARY)) { return new SummaryRecordType(identifier, title, litType , bboxes, keywords, format, modified, _abstract); } else { return fullResult; } // for an element name mode } else { final RecordType result = new RecordType(); for (QName qn : elementName) { try { final Method getter = ReflectionUtilities.getGetterFromName(qn.getLocalPart(), RecordType.class); final Object param = ReflectionUtilities.invokeMethod(fullResult, getter); Method setter = null; if (param != null) { setter =ReflectionUtilities.getSetterFromName(qn.getLocalPart(), param.getClass(), RecordType.class); } if (setter != null) { ReflectionUtilities.invokeMethod(setter, result, param); } else { if (param != null) { LOGGER.warning("No setter have been found for attribute " + qn.getLocalPart() +" of type " + param.getClass() + " in the class RecordType"); } } } catch (IllegalArgumentException ex) { LOGGER.warning("illegal argument exception while invoking the method get" + StringUtilities.firstToUpper(qn.getLocalPart()) + " in the RecordType class"); } } return result; } } /** * Create a bounding box from a geographiqueElement Value */ private BoundingBoxType createBoundingBoxFromValue(final String idValue, final FullRecord f, final Standard mainStandard) throws MD_IOException { Double southValue = null; Double eastValue = null; Double westValue = null; Double northValue = null; String crs = null; final String typePrefix; if (Standard.ISO_19115.equals(mainStandard)) { typePrefix = "ISO 19115:MD_Metadata:"; } else if (Standard.ISO_19115_2.equals(mainStandard)) { typePrefix = "ISO 19115-2:MI_Metadata:"; } else { throw new MD_IOException("unexpected main standard:" + mainStandard); } String currentParsed = null; try { //we get the east value final List<Value> eastValues = f.getValueFromPath(typePrefix + "identificationInfo:extent:geographicElement2:eastBoundLongitude"); for (Value v: eastValues) { final Value parentValue = v.getParent(); if (v instanceof TextValue && parentValue.getIdValue().equals(idValue)) { currentParsed = ((TextValue)v).getValue(); eastValue = Double.parseDouble(currentParsed); } } //we get the east value final List<Value> westValues = f.getValueFromPath(typePrefix + "identificationInfo:extent:geographicElement2:westBoundLongitude"); for (Value v: westValues) { final Value parentValue = v.getParent(); if (v instanceof TextValue && parentValue.getIdValue().equals(idValue)) { currentParsed = ((TextValue)v).getValue(); westValue = Double.parseDouble(currentParsed); } } //we get the north value final List<Value> northValues = f.getValueFromPath(typePrefix + "identificationInfo:extent:geographicElement2:northBoundLatitude"); for (Value v: northValues) { final Value parentValue = v.getParent(); if (v instanceof TextValue && parentValue.getIdValue().equals(idValue)) { currentParsed = ((TextValue)v).getValue(); northValue = Double.parseDouble(currentParsed); } } //we get the south value final List<Value> southValues = f.getValueFromPath(typePrefix + "identificationInfo:extent:geographicElement2:southBoundLatitude"); for (Value v: southValues) { final Value parentValue = v.getParent(); if (v instanceof TextValue && parentValue.getIdValue().equals(idValue)) { currentParsed = ((TextValue)v).getValue(); southValue = Double.parseDouble(currentParsed); } } } catch (NumberFormatException ex) { if (currentParsed != null && !currentParsed.isEmpty()) { LOGGER.log(Level.WARNING, "unable to parse a double in bounding box value:\n{0}", ex.getMessage()) ; } } if (eastValue != null && westValue != null && northValue != null && southValue != null) { final BoundingBoxType result = new BoundingBoxType("EPSG:4326", eastValue, southValue, westValue, northValue); LOGGER.finer("boundingBox created"); return result; } else { LOGGER.finer("boundingBox null"); return null; } } /** * {@inheritDoc} */ @Override public List<QName> getAdditionalQueryableQName() { return Arrays.asList(DEGREE_QNAME, ACCESS_CONSTRAINTS_QNAME, OTHER_CONSTRAINTS_QNAME, INS_CLASSIFICATION_QNAME, CONDITION_APPLYING_TO_ACCESS_AND_USE_QNAME, METADATA_POINT_OF_CONTACT_QNAME, LINEAGE_QNAME, SPECIFICATION_TITLE_QNAME, SPECIFICATION_DATE_QNAME, SPECIFICATION_DATETYPE_QNAME); } /** * {@inheritDoc} */ @Override public Map<String, List<String>> getAdditionalQueryablePathMap() { return INSPIRE_QUERYABLE; } /** * {@inheritDoc} */ @Override public Map<String, URI> getConceptMap() { return conceptMap; } /** * {@inheritDoc} */ @Override public String[] executeEbrimSQLQuery(final String sqlQuery) throws MetadataIoException { try { final Set<String> results = mdReader.executeFilterQuery(sqlQuery); return results.toArray(new String[results.size()]); } catch (MD_IOException ex) { throw new MetadataIoException("The service has throw an SQL exception while making ebrim request:" + '\n' + "Cause: " + ex.getMessage(), NO_APPLICABLE_CODE); } } }