/* * 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.netcdf; import java.io.File; import java.lang.reflect.Method; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import java.util.TimeZone; import java.util.logging.Level; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.sis.internal.jaxb.LegacyNamespaces; import org.apache.sis.metadata.iso.DefaultMetadata; import org.apache.sis.xml.XML; import org.constellation.generic.database.Automatic; import org.constellation.jaxb.MarshallWarnings; import static org.constellation.metadata.CSWConstants.NETCDF_EXT; import static org.constellation.metadata.CSWQueryable.DUBLIN_CORE_QUERYABLE; import static org.constellation.metadata.CSWQueryable.ISO_QUERYABLE; import org.constellation.metadata.index.generic.GenericIndexer; import org.constellation.metadata.io.AbstractMetadataReader; import org.constellation.metadata.io.CSWMetadataReader; import org.constellation.metadata.io.ElementSetType; import org.constellation.metadata.io.MetadataIoException; import org.constellation.metadata.io.MetadataType; import org.constellation.metadata.utils.Utils; import org.constellation.util.ReflectionUtilities; import org.geotoolkit.coverage.io.CoverageStoreException; import org.geotoolkit.coverage.io.ImageCoverageReader; import org.geotoolkit.csw.xml.DomainValues; import static org.geotoolkit.csw.xml.TypeNames.METADATA_QNAME; 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 static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Creator_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Date_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Format_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Identifier_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Language_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Publisher_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Subject_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Title_QNAME; import static org.geotoolkit.dublincore.xml.v2.elements.ObjectFactory._Type_QNAME; import org.geotoolkit.dublincore.xml.v2.elements.SimpleLiteral; import static org.geotoolkit.dublincore.xml.v2.terms.ObjectFactory._Abstract_QNAME; import static org.geotoolkit.dublincore.xml.v2.terms.ObjectFactory._Modified_QNAME; import org.geotoolkit.ebrim.xml.EBRIMMarshallerPool; import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_PARAMETER_VALUE; import static org.geotoolkit.ows.xml.OWSExceptionCode.NO_APPLICABLE_CODE; import static org.geotoolkit.ows.xml.OWSExceptionCode.OPERATION_NOT_SUPPORTED; import org.geotoolkit.ows.xml.v100.BoundingBoxType; import static org.geotoolkit.ows.xml.v100.ObjectFactory._BoundingBox_QNAME; import org.opengis.metadata.citation.Responsibility; import org.opengis.metadata.citation.ResponsibleParty; import org.opengis.metadata.citation.Role; import org.opengis.metadata.distribution.Distribution; import org.opengis.metadata.distribution.Distributor; import org.opengis.metadata.distribution.Format; import org.opengis.metadata.extent.Extent; import org.opengis.metadata.extent.GeographicBoundingBox; import org.opengis.metadata.extent.GeographicExtent; import org.opengis.metadata.identification.DataIdentification; import org.opengis.metadata.identification.Identification; import org.opengis.metadata.identification.Keywords; import org.opengis.metadata.identification.TopicCategory; import org.opengis.metadata.maintenance.ScopeCode; import org.opengis.util.InternationalString; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * * * @author Guilhem Legal (Geomatys) * @since 0.8.4 */ public class NetCDFMetadataReader extends AbstractMetadataReader implements CSWMetadataReader { /** * The directory containing the data XML files. */ private final File dataDirectory; private static final String METAFILE_MSG = "The netcdf file : "; /** * A date formatter used to display the Date object for Dublin core translation. */ private static final DateFormat FORMATTER; static { FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); } private final String CURRENT_EXT; private final boolean usePathAsIdentifier; private static final TimeZone tz = TimeZone.getTimeZone("GMT+2:00"); private Locale locale = null; /** * Build a new CSW NetCDF File Reader. * * @param configuration A generic configuration object containing a directory path * in the configuration.dataDirectory field. * * @throws MetadataIoException If the configuration object does * not contains an existing directory path in the configuration.dataDirectory field. * If the creation of a MarshallerPool throw a JAXBException. */ public NetCDFMetadataReader(final Automatic configuration) throws MetadataIoException { super(true, false); dataDirectory = configuration.getDataDirectory(); if (dataDirectory == null) { throw new MetadataIoException("cause: unable to find the data directory", NO_APPLICABLE_CODE); } else if (!dataDirectory.exists()) { boolean created = dataDirectory.mkdir(); if (!created) { throw new MetadataIoException("cause: unable to create the unexisting data directory:" + dataDirectory.getPath(), NO_APPLICABLE_CODE); } } final String extension = configuration.getParameter("netcdfExtension"); if (extension != null) { CURRENT_EXT = extension; } else { CURRENT_EXT = NETCDF_EXT; } final String usePathAsIdentifierValue = configuration.getParameter("usePathAsIdentifier"); if (usePathAsIdentifierValue != null) { usePathAsIdentifier = Boolean.valueOf(usePathAsIdentifierValue); } else { usePathAsIdentifier = false; } if (configuration.getEnableThread() != null && !configuration.getEnableThread().isEmpty()) { final boolean t = Boolean.parseBoolean(configuration.getEnableThread()); if (t) { LOGGER.info("parrallele treatment enabled"); } setIsThreadEnabled(t); } if (configuration.getEnableCache() != null && !configuration.getEnableCache().isEmpty()) { final boolean c = Boolean.parseBoolean(configuration.getEnableCache()); if (!c) { LOGGER.info("cache system have been disabled"); } setIsCacheEnabled(c); } final String localeString = configuration.getParameter("locale"); if (localeString != null) { locale = Locale.forLanguageTag(localeString); } } /** * {@inheritDoc} */ @Override public Node getMetadata(final String identifier, final MetadataType mode) throws MetadataIoException { return getMetadata(identifier, mode, ElementSetType.FULL, new ArrayList<QName>()); } /** * {@inheritDoc} */ @Override public Node getMetadata(final String identifier, final MetadataType mode, final ElementSetType type, final List<QName> elementName) throws MetadataIoException { Object obj = null; if (isCacheEnabled()) { obj = getFromCache(identifier); } if (obj == null) { obj = getObjectFromFile(identifier); } if (obj instanceof DefaultMetadata && mode == MetadataType.DUBLINCORE) { obj = translateISOtoDC((DefaultMetadata)obj, type, elementName); } else if (obj instanceof RecordType && mode == MetadataType.DUBLINCORE) { obj = applyElementSet((RecordType)obj, type, elementName); } // marshall to DOM if (obj != null) { return writeObjectInNode(obj, mode); } return null; } @Override public boolean existMetadata(final String identifier) throws MetadataIoException { final File metadataFile; if (usePathAsIdentifier) { metadataFile = getFileFromPathIdentifier(identifier, dataDirectory, CURRENT_EXT); } else { metadataFile = getFileFromIdentifier(identifier, dataDirectory, CURRENT_EXT); } return metadataFile != null && metadataFile.exists(); } /** * Try to find a file named identifier.nc or identifier recursively * in the specified directory and its sub-directories. * * @param identifier The metadata identifier. * @param directory The current directory to explore. * @param ext file extension. * @return */ public static File getFileFromIdentifier(final String identifier, final File directory, final String ext) { // 1) try to find the file in the current directory File metadataFile = new File (directory, identifier + ext); // 2) trying without the extension if (!metadataFile.exists()) { metadataFile = new File (directory, identifier); } // 3) trying by replacing ':' by '-' (for windows platform who don't accept ':' in file name) if (!metadataFile.exists()) { final String windowsIdentifier = identifier.replace(':', '-'); metadataFile = new File (directory, windowsIdentifier + ext); } if (metadataFile.exists()) { return metadataFile; } else { for (File child : directory.listFiles()) { if (child.isDirectory()) { final File result = getFileFromIdentifier(identifier, child, ext); if (result != null && result.exists()) { return result; } } } } return null; } /** * Try to find a file named identifier.nc or identifier recursively * in the specified directory and its sub-directories. * * @param identifier The metadata identifier. * @param directory The current directory to explore. * @param ext File extension. * @return */ public static File getFileFromPathIdentifier(final String identifier, final File directory, final String ext) { // if where are in the final directory if (identifier.indexOf(':') == -1) { // 1) try to find the file in the current directory File metadataFile = new File (directory, identifier + ext); // 2) trying without the extension if (!metadataFile.exists()) { metadataFile = new File (directory, identifier); } // 3) trying by replacing ':' by '-' (for windows platform who don't accept ':' in file name) if (!metadataFile.exists()) { final String windowsIdentifier = identifier.replace(':', '-'); metadataFile = new File (directory, windowsIdentifier + ext); } if (metadataFile.exists()) { return metadataFile; } else { LOGGER.warning("unable to find the metadata:" + identifier + " in the directory:" + directory.getPath()); return null; } } else { final int separator = identifier.indexOf(':'); final String directoryName = identifier.substring(0, separator); final File child = new File(directory, directoryName); if (child.isDirectory()) { final String childIdentifier = identifier.substring(separator + 1); return getFileFromPathIdentifier(childIdentifier, child, ext); } else { LOGGER.log(Level.WARNING, "{0} is not a directory.", child.getPath()); return null; } } } /** * Unmarshall The file designed by the path dataDirectory/identifier.nc * If the file is not present or if it is impossible to unmarshall it it return an exception. * * @param identifier the metadata identifier * @return A unmarshalled metadata object. * @throws org.constellation.ws.MetadataIoException */ private Object getObjectFromFile(final String identifier) throws MetadataIoException { final File metadataFile; if (usePathAsIdentifier) { metadataFile = getFileFromPathIdentifier(identifier, dataDirectory, CURRENT_EXT); } else { metadataFile = getFileFromIdentifier(identifier, dataDirectory, CURRENT_EXT); } if (metadataFile != null && metadataFile.exists()) { final ImageCoverageReader reader = new ImageCoverageReader(); if (locale != null) { reader.setLocale(locale); } try { reader.setInput(metadataFile); final Object obj = reader.getMetadata(); Utils.setIdentifier(identifier, obj); return obj; } catch (CoverageStoreException | IllegalArgumentException ex) { throw new MetadataIoException(METAFILE_MSG + metadataFile.getName() + " can not be read\ncause: " + ex.getMessage(), ex, INVALID_PARAMETER_VALUE); } finally { try { reader.dispose(); } catch (CoverageStoreException ex) { LOGGER.log(Level.WARNING, null, ex); } } } throw new MetadataIoException(METAFILE_MSG + identifier + ".nc is not present", INVALID_PARAMETER_VALUE); } /** * Apply the elementSet (Brief, Summary or full) or the custom elementSetName on the specified record. * * @param record A dublinCore record. * @param type The ElementSetType to apply on this record. * @param elementName A list of QName corresponding to the requested attribute. this parameter is ignored if type is not null. * * @return A record object. * @throws MetadataIoException If the type and the element name are null. */ private AbstractRecordType applyElementSet(final RecordType record, final ElementSetType type, final List<QName> elementName) throws MetadataIoException { if (type != null) { if (type.equals(ElementSetType.SUMMARY)) { return record.toSummary(); } else if (type.equals(ElementSetType.BRIEF)) { return record.toBrief(); } else { return record; } } else if (elementName != null) { final RecordType customRecord = new RecordType(); for (QName qn : elementName) { if (qn != null) { try { final Method getter = ReflectionUtilities.getGetterFromName(qn.getLocalPart(), RecordType.class); final Object param = ReflectionUtilities.invokeMethod(record, getter); final Method setter; if (param != null) { setter = ReflectionUtilities.getSetterFromName(qn.getLocalPart(), param.getClass(), RecordType.class); } else { continue; } if (setter != null) { ReflectionUtilities.invokeMethod(setter, customRecord, param); } else { final String paramDesc = param.getClass().getSimpleName(); LOGGER.warning("No setter have been found for attribute " + qn.getLocalPart() +" of type " + paramDesc + " in the class RecordType"); } } catch (IllegalArgumentException ex) { LOGGER.log(Level.WARNING, "illegal argument exception while invoking the method for attribute{0} in the classe RecordType", qn.getLocalPart()); } } else { LOGGER.warning("An elementName was null."); } } return customRecord; } else { throw new MetadataIoException("No ElementSet or Element name specified"); } } /** * Translate A ISO 19139 object into a DublinCore representation. * The elementSet (Brief, Summary or full) or the custom elementSetName is applied. * * @param metadata * @param type * @param elementName * @return */ private AbstractRecordType translateISOtoDC(final DefaultMetadata metadata, final ElementSetType type, final List<QName> elementName) { if (metadata != null) { final RecordType customRecord = new RecordType(); /* * BRIEF part */ final SimpleLiteral identifier = new SimpleLiteral(metadata.getFileIdentifier()); if (elementName != null && elementName.contains(_Identifier_QNAME)) { customRecord.setIdentifier(identifier); } SimpleLiteral title = null; //TODO see for multiple identification for (Identification identification: metadata.getIdentificationInfo()) { if (identification.getCitation() != null && identification.getCitation().getTitle() != null) { title = new SimpleLiteral(identification.getCitation().getTitle().toString()); } } if (elementName != null && elementName.contains(_Title_QNAME)) { customRecord.setTitle(title); } SimpleLiteral dataType = null; //TODO see for multiple hierarchyLevel for (ScopeCode code: metadata.getHierarchyLevels()) { dataType = new SimpleLiteral(code.identifier()); } if (elementName != null && elementName.contains(_Type_QNAME)) { customRecord.setType(dataType); } final List<BoundingBoxType> bboxes = new ArrayList<>(); for (Identification identification: metadata.getIdentificationInfo()) { if (identification instanceof DataIdentification) { final DataIdentification dataIdentification = (DataIdentification) identification; for (Extent extent : dataIdentification.getExtents()) { for (GeographicExtent geoExtent :extent.getGeographicElements()) { if (geoExtent instanceof GeographicBoundingBox) { final GeographicBoundingBox bbox = (GeographicBoundingBox) geoExtent; // TODO find CRS bboxes.add(new BoundingBoxType("EPSG:4326", bbox.getWestBoundLongitude(), bbox.getSouthBoundLatitude(), bbox.getEastBoundLongitude(), bbox.getNorthBoundLatitude())); } } } } } if (elementName != null && elementName.contains(_BoundingBox_QNAME)) { customRecord.setSimpleBoundingBox(bboxes); } if (type != null && type.equals(ElementSetType.BRIEF)) return new BriefRecordType(identifier, title, dataType, bboxes); /* * SUMMARY part */ final List<SimpleLiteral> abstractt = new ArrayList<>(); for (Identification identification: metadata.getIdentificationInfo()) { if (identification.getAbstract() != null) { abstractt.add(new SimpleLiteral(identification.getAbstract().toString())); } } if (elementName != null && elementName.contains(_Abstract_QNAME)) { customRecord.setAbstract(abstractt); } final List<SimpleLiteral> subjects = new ArrayList<>(); for (Identification identification: metadata.getIdentificationInfo()) { for (Keywords kw :identification.getDescriptiveKeywords()) { for (InternationalString str : kw.getKeywords()) { subjects.add(new SimpleLiteral(str.toString())); } } if (identification instanceof DataIdentification) { final DataIdentification dataIdentification = (DataIdentification) identification; for (TopicCategory tc : dataIdentification.getTopicCategories()) { subjects.add(new SimpleLiteral(tc.identifier())); } } } if (elementName != null && elementName.contains(_Subject_QNAME)) { customRecord.setSubject(subjects); } List<SimpleLiteral> formats = new ArrayList<>(); for (Identification identification: metadata.getIdentificationInfo()) { for (Format f :identification.getResourceFormats()) { if (f == null || f.getName() == null) { continue; } formats.add(new SimpleLiteral(f.getName().toString())); } } if (formats.isEmpty()) { formats = null; } if (elementName != null && elementName.contains(_Format_QNAME)) { customRecord.setFormat(formats); } final SimpleLiteral modified; if (metadata.getDateStamp() != null) { String dateValue; synchronized (FORMATTER) { dateValue = FORMATTER.format(metadata.getDateStamp()); } dateValue = dateValue.substring(0, dateValue.length() - 2); dateValue = dateValue + ":00"; modified = new SimpleLiteral(dateValue); if (elementName != null && elementName.contains(_Modified_QNAME)) { customRecord.setModified(modified); } } else { modified = null; } if (type != null && type.equals(ElementSetType.SUMMARY)) return new SummaryRecordType(identifier, title, dataType, bboxes, subjects, formats, modified, abstractt); final SimpleLiteral date = modified; if (elementName != null && elementName.contains(_Date_QNAME)) { customRecord.setDate(date); } List<SimpleLiteral> creator = new ArrayList<>(); for (Identification identification: metadata.getIdentificationInfo()) { for (Responsibility rp :identification.getPointOfContacts()) { if (Role.ORIGINATOR.equals(rp.getRole())) { creator.add(new SimpleLiteral(((ResponsibleParty) rp).getOrganisationName().toString())); } } } if (creator.isEmpty()) creator = null; if (elementName != null && elementName.contains(_Creator_QNAME)) { customRecord.setCreator(creator); } // TODO multiple SimpleLiteral distributor = null; for (final Distribution distribution : metadata.getDistributionInfo()) { for (Distributor dis :distribution.getDistributors()) { final ResponsibleParty disRP = (ResponsibleParty) dis.getDistributorContact(); if (disRP != null) { InternationalString name = disRP.getOrganisationName(); if (name != null) { distributor = new SimpleLiteral(name.toString()); break; } } } } if (elementName != null && elementName.contains(_Publisher_QNAME)) { customRecord.setPublisher(distributor); } final SimpleLiteral language; if (metadata.getLanguage() != null) { language = new SimpleLiteral(metadata.getLanguage().getISO3Language()); if (elementName != null && elementName.contains(_Language_QNAME)) { customRecord.setLanguage(language); } } else { language = null; } // TODO final SimpleLiteral spatial = null; final SimpleLiteral references = null; if (type != null && type.equals(ElementSetType.FULL)) return new RecordType(identifier, title, dataType, subjects, formats, modified, date, abstractt, bboxes, creator, distributor, language, spatial, references); return customRecord; } return null; } /** * {@inheritDoc} */ @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(); final List<String> paths; if (ISO_QUERYABLE.get(token) != null) { paths = ISO_QUERYABLE.get(token); } else if (DUBLIN_CORE_QUERYABLE.get(token) != null) { paths = DUBLIN_CORE_QUERYABLE.get(token); } else { throw new MetadataIoException("The property " + token + " is not queryable", INVALID_PARAMETER_VALUE, "propertyName"); } if (!paths.isEmpty()) { final List<String> values = getAllValuesFromPaths(paths, dataDirectory, null); final ListOfValuesType listValues = new ListOfValuesType(values); final DomainValuesType value = new DomainValuesType(null, token, listValues, METADATA_QNAME); responseList.add(value); } else { throw new MetadataIoException("The property " + token + " is not queryable for now", INVALID_PARAMETER_VALUE, "propertyName"); } } return responseList; } /** * Return all the String values corresponding to the specified list of path through the metadata. * * @param paths * @return * @throws MetadataIoException */ private List<String> getAllValuesFromPaths(final List<String> paths, final File directory, final String parentIdentifierPrefix) throws MetadataIoException { final String identifierPrefix = conputeIdentifierPrefix(directory, parentIdentifierPrefix); final List<String> result = new ArrayList<>(); final ImageCoverageReader reader = new ImageCoverageReader(); if (locale != null) { reader.setLocale(locale); } try { for (File metadataFile : directory.listFiles()) { final String fileName = metadataFile.getName(); if (fileName.endsWith(CURRENT_EXT)) { try { final String identifier = computeIdentifier(fileName, identifierPrefix); reader.setInput(metadataFile); final Object metadata = reader.getMetadata(); Utils.setIdentifier(identifier, metadata); final List<Object> value = GenericIndexer.extractValues(metadata, paths); if (value != null && !value.equals(Arrays.asList("null"))) { for (Object obj : value) { result.add(obj.toString()); } } //continue to the next file } catch (CoverageStoreException | IllegalArgumentException ex) { LOGGER.warning(METAFILE_MSG + metadataFile.getName() + " can not be read\ncause: " + ex.getMessage()); } } else if (metadataFile.isDirectory()) { result.addAll(getAllValuesFromPaths(paths, metadataFile, identifierPrefix)); } else { //do not throw exception just skipping //throw new MetadataIoException(METAFILE_MSG + f.getPath() + " does not ands with " + CURRENT_EXT + " or is not a directory", INVALID_PARAMETER_VALUE); } } } finally { try { reader.dispose(); } catch (CoverageStoreException ex) { LOGGER.log(Level.WARNING, null, ex); } } Collections.sort(result); return result; } /** * {@inheritDoc} */ @Override public void destroy() { } /** * {@inheritDoc} */ @Override public String[] executeEbrimSQLQuery(final String sqlQuery) throws MetadataIoException { throw new MetadataIoException("Ebrim query are not supported int the FILESYSTEM mode.", OPERATION_NOT_SUPPORTED); } /** * {@inheritDoc} */ @Override public List<? extends Object> getAllEntries() throws MetadataIoException { return getAllEntries(dataDirectory, null); } /** * */ private List<? extends Object> getAllEntries(final File directory, final String parentIdentifierPrefix) throws MetadataIoException { final String identifierPrefix = conputeIdentifierPrefix(directory, parentIdentifierPrefix); final List<Object> results = new ArrayList<>(); final ImageCoverageReader reader = new ImageCoverageReader(); if (locale != null) { reader.setLocale(locale); } for (File f : directory.listFiles()) { final String fileName = f.getName(); if (fileName.endsWith(CURRENT_EXT)) { final String identifier = computeIdentifier(fileName, identifierPrefix); try { reader.setInput(f); final Object metadata = reader.getMetadata(); Utils.setIdentifier(identifier, metadata); if (isCacheEnabled()) { addInCache(identifier, metadata); } results.add(metadata); } catch (CoverageStoreException ex) { // throw or continue to the next file? throw new MetadataIoException(METAFILE_MSG + f.getPath() + " can not be read\ncause: " + ex.getMessage(), ex, INVALID_PARAMETER_VALUE); } } else if (f.isDirectory()) { results.addAll(getAllEntries(f, identifierPrefix)); } else { //do not throw exception just skipping //throw new MetadataIoException(METAFILE_MSG + f.getPath() + " does not ands with " + CURRENT_EXT + " or is not a directory", INVALID_PARAMETER_VALUE); } } try { reader.dispose(); } catch (CoverageStoreException ex) { // throw or continue to the next file? LOGGER.log(Level.WARNING, "Unable to close the imageCoverageReader", ex); } return results; } @Override public Iterator<String> getIdentifierIterator() throws MetadataIoException { final List<String> results = getAllIdentifiers(); return results.iterator(); } /** * {@inheritDoc} */ @Override public List<String> getAllIdentifiers() throws MetadataIoException { return getAllIdentifiers(dataDirectory, null); } @Override public int getEntryCount() throws MetadataIoException { return getAllIdentifiers(dataDirectory, null).size(); } /** * find recursively the files names used as record identifier. * * @param directory * @param parentIdentifierPrefix * @return * @throws MetadataIoException */ private List<String> getAllIdentifiers(final File directory, final String parentIdentifierPrefix) throws MetadataIoException { final String identifierPrefix = conputeIdentifierPrefix(directory, parentIdentifierPrefix); final List<String> results = new ArrayList<>(); if (directory != null && directory.exists()) { for (File f : directory.listFiles()) { final String fileName = f.getName(); if (fileName.endsWith(CURRENT_EXT)) { results.add(computeIdentifier(fileName, identifierPrefix)); } else if (f.isDirectory()){ results.addAll(getAllIdentifiers(f, identifierPrefix)); } else { //do not throw exception just skipping //throw new MetadataIoException(METAFILE_MSG + f.getPath() + " does not ands with " + CURRENT_EXT + " or is not a directory", INVALID_PARAMETER_VALUE); } } } return results; } private String computeIdentifier(final String fileName, final String identifierPrefix) { if (usePathAsIdentifier) { return identifierPrefix + ':' + fileName.substring(0, fileName.lastIndexOf(CURRENT_EXT)); } else { return fileName.substring(0, fileName.lastIndexOf(CURRENT_EXT)); } } private String conputeIdentifierPrefix(final File directory, final String identifierPrefix) { if (usePathAsIdentifier) { if (identifierPrefix == null) { return ""; } else { return identifierPrefix + ':' + directory.getName(); } } return null; } /** * {@inheritDoc} */ @Override public List<MetadataType> getSupportedDataTypes() { return Arrays.asList( MetadataType.ISO_19115, MetadataType.DUBLINCORE, MetadataType.EBRIM, MetadataType.ISO_19110); } /** * Return the list of Additional queryable element (0 in MDWeb). */ @Override public List<QName> getAdditionalQueryableQName() { return new ArrayList<>(); } /** * {@inheritDoc} */ @Override public Map<String, List<String>> getAdditionalQueryablePathMap() { return new HashMap<>(); } protected Node writeObjectInNode(final Object obj, final MetadataType mode) throws MetadataIoException { final boolean replace = mode == MetadataType.ISO_19115; try { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); final DocumentBuilder docBuilder = dbf.newDocumentBuilder(); final Document document = docBuilder.newDocument(); final Marshaller marshaller = EBRIMMarshallerPool.getInstance().acquireMarshaller(); final MarshallWarnings warnings = new MarshallWarnings(); marshaller.setProperty(XML.CONVERTER, warnings); marshaller.setProperty(XML.TIMEZONE, tz); marshaller.setProperty(LegacyNamespaces.APPLY_NAMESPACE_REPLACEMENTS, replace); marshaller.setProperty(XML.GML_VERSION, LegacyNamespaces.VERSION_3_2_1); if (locale != null) { marshaller.setProperty(XML.LOCALE, locale); } marshaller.marshal(obj, document); return document.getDocumentElement(); } catch (ParserConfigurationException | JAXBException ex) { throw new MetadataIoException(ex); } } }