/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2016, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotoolkit.metadata.dimap; import org.opengis.coverage.SampleDimensionType; import org.opengis.coverage.grid.GridEnvelope; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Geometry; import org.opengis.geometry.coordinate.GeometryFactory; import org.opengis.metadata.acquisition.AcquisitionInformation; import org.opengis.metadata.citation.DateType; import org.opengis.metadata.citation.Role; import org.opengis.metadata.constraint.Restriction; import org.opengis.metadata.content.ContentInformation; import org.opengis.metadata.content.RangeDimension; import org.opengis.metadata.content.TransferFunctionType; import org.opengis.metadata.extent.Extent; import org.opengis.metadata.identification.Identification; import org.opengis.metadata.lineage.Lineage; import org.opengis.metadata.lineage.ProcessStep; import org.opengis.metadata.quality.DataQuality; import org.opengis.metadata.spatial.Dimension; import org.opengis.metadata.spatial.DimensionNameType; import org.opengis.metadata.spatial.SpatialRepresentation; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform1D; import org.opengis.referencing.operation.TransformException; import org.opengis.util.FactoryException; import org.opengis.util.MemberName; import org.opengis.util.TypeName; import org.apache.sis.internal.jaxb.gmi.MI_Metadata; import org.apache.sis.measure.NumberRange; import org.apache.sis.metadata.iso.DefaultIdentifier; import org.apache.sis.metadata.iso.DefaultMetadata; import org.apache.sis.metadata.iso.acquisition.DefaultAcquisitionInformation; import org.apache.sis.metadata.iso.acquisition.DefaultInstrument; import org.apache.sis.metadata.iso.acquisition.DefaultOperation; import org.apache.sis.metadata.iso.acquisition.DefaultPlatform; import org.apache.sis.metadata.iso.citation.DefaultCitation; import org.apache.sis.metadata.iso.citation.DefaultCitationDate; import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty; import org.apache.sis.metadata.iso.constraint.DefaultLegalConstraints; import org.apache.sis.metadata.iso.content.AbstractContentInformation; import org.apache.sis.metadata.iso.content.DefaultBand; import org.apache.sis.metadata.iso.content.DefaultImageDescription; import org.apache.sis.metadata.iso.distribution.DefaultFormat; import org.apache.sis.metadata.iso.extent.DefaultBoundingPolygon; import org.apache.sis.metadata.iso.extent.DefaultExtent; import org.apache.sis.metadata.iso.extent.DefaultGeographicDescription; import org.apache.sis.metadata.iso.identification.AbstractIdentification; import org.apache.sis.metadata.iso.identification.DefaultBrowseGraphic; import org.apache.sis.metadata.iso.identification.DefaultDataIdentification; import org.apache.sis.metadata.iso.identification.DefaultResolution; import org.apache.sis.metadata.iso.lineage.DefaultAlgorithm; import org.apache.sis.metadata.iso.lineage.DefaultLineage; import org.apache.sis.metadata.iso.lineage.DefaultProcessStep; import org.apache.sis.metadata.iso.lineage.DefaultProcessing; import org.apache.sis.metadata.iso.quality.DefaultDataQuality; import org.apache.sis.metadata.iso.spatial.AbstractSpatialRepresentation; import org.apache.sis.metadata.iso.spatial.DefaultDimension; import org.apache.sis.metadata.iso.spatial.DefaultGridSpatialRepresentation; import org.apache.sis.referencing.operation.transform.TransferFunction; import org.apache.sis.util.iso.DefaultNameFactory; import org.apache.sis.util.iso.SimpleInternationalString; import org.apache.sis.util.logging.Logging; import org.geotoolkit.coverage.Category; import org.geotoolkit.coverage.GridSampleDimension; import org.geotoolkit.coverage.TypeMap; import org.geotoolkit.coverage.grid.GeneralGridEnvelope; import org.geotoolkit.geometry.isoonjts.GeometryUtils; import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.geometry.JTSGeometryFactory; import org.geotoolkit.lang.Static; import org.apache.sis.referencing.CRS; import org.geotoolkit.referencing.operation.transform.WarpTransform2D; import org.geotoolkit.temporal.object.ISODateParser; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.measure.Unit; import javax.media.jai.Warp; import javax.media.jai.WarpAffine; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.sis.measure.Units; import static org.geotoolkit.metadata.dimap.DimapConstants.*; import static org.geotoolkit.util.DomUtilities.firstElement; import static org.geotoolkit.util.DomUtilities.getListElements; import static org.geotoolkit.util.DomUtilities.textAttributeValueSafe; import static org.geotoolkit.util.DomUtilities.textValueSafe; /** * Utility class to access usable objects from a dimap file. * * @author Johann Sorel (Geomatys) * @author Christophe Mourette (Geomatys) * @module */ @SuppressWarnings("restriction") public final class DimapAccessor extends Static { private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.metadata.dimap"); private DimapAccessor() { } /** * Read the Coordinate Reference System of the grid. * Those informations are provided by the CoordinateReferenceSystem tag. * * @param doc * @return CoordinateReferenceSystem * @throws org.opengis.referencing.NoSuchAuthorityCodeException * @throws org.opengis.util.FactoryException */ public static CoordinateReferenceSystem readCRS(final Element doc) throws NoSuchAuthorityCodeException, FactoryException { final Element ele = firstElement(doc, TAG_CRS); final Element code = firstElement(ele, TAG_HORIZONTAL_CS_CODE); return CRS.forCode(code.getTextContent()); } public static GridEnvelope getGridExtent2D(Element doc) { final Element datasetFrame = firstElement(doc, TAG_DATASET_FRAME); final List<Element> vertexs = getListElements(datasetFrame, TAG_VERTEX); int[] low = new int[2]; int[] high = new int[2]; for (final Element vertex : vertexs) { final Integer row = textValueSafe(vertex, TAG_FRAME_ROW, Integer.class); final Integer col = textValueSafe(vertex, TAG_FRAME_COL, Integer.class); low[0] = Math.min(low[0], row); low[1] = Math.min(low[1], col); high[0] = Math.max(high[0], row); high[1] = Math.max(high[1], col); } return new GeneralGridEnvelope(low, high, false); } /** * Read the Grid to CRS transform. * Those informations are provided by the Geoposition tag. * * @param doc * @return AffineTransform * @throws org.opengis.util.FactoryException * @throws org.opengis.referencing.operation.TransformException */ public static AffineTransform readGridToCRS2D(final Element doc) throws FactoryException, TransformException { final Element ele = firstElement(doc, TAG_GEOPOSITION); final Element insert = firstElement(ele, TAG_GEOPOSITION_INSERT); final Element points = firstElement(ele, TAG_GEOPOSITION_POINTS); final Element affine = firstElement(ele, TAG_GEOPOSITION_AFFINE); if (insert != null) { // X = ULXMAP + XDIM * i // Y = ULYMAP - YDIM * j final double ulx = textValueSafe(insert, TAG_ULXMAP, Double.class); final double uly = textValueSafe(insert, TAG_ULYMAP, Double.class); final double xdim = textValueSafe(insert, TAG_XDIM, Double.class); final double ydim = textValueSafe(insert, TAG_YDIM, Double.class); return new AffineTransform(xdim, 0, 0, -ydim, ulx, uly); } else if (affine != null) { // X (CRS) = X0 + X1 * X(Data) + X2 * Y(Data) // Y (CRS) = Y0 + Y1 * X(Data) + Y2 * Y(Data) final double x0 = textValueSafe(affine, TAG_AFFINE_X0, Double.class); final double x1 = textValueSafe(affine, TAG_AFFINE_X1, Double.class); final double x2 = textValueSafe(affine, TAG_AFFINE_X2, Double.class); final double y0 = textValueSafe(affine, TAG_AFFINE_Y0, Double.class); final double y1 = textValueSafe(affine, TAG_AFFINE_Y1, Double.class); final double y2 = textValueSafe(affine, TAG_AFFINE_Y2, Double.class); return new AffineTransform(x0, y0, x1, y1, x2, y2); } else if (points != null) { // transformation in not accurate if the method has been defined. // read the points and calculate an average transform from them. final NodeList tiePoints = ele.getElementsByTagName(TAG_TIE_POINT); final List<Point2D> sources = new ArrayList<>(); final List<Point2D> dests = new ArrayList<>(); for (int i = 0, n = tiePoints.getLength(); i < n; i++) { final Element vertex = (Element) tiePoints.item(i); final double coordX = textValueSafe(vertex, TAG_TIE_POINT_CRS_X, Double.class); final double coordY = textValueSafe(vertex, TAG_TIE_POINT_CRS_Y, Double.class); final int dataY = textValueSafe(vertex, TAG_TIE_POINT_DATA_X, Double.class).intValue(); final int dataX = textValueSafe(vertex, TAG_TIE_POINT_DATA_Y, Double.class).intValue(); dests.add(new Point2D.Double(coordX, coordY)); sources.add(new Point2D.Double(dataX, dataY)); } final WarpTransform2D warptrs = new WarpTransform2D( sources.toArray(new Point2D[sources.size()]), dests.toArray(new Point2D[dests.size()]), 1); final Warp warp = warptrs.getWarp(); if (warp instanceof WarpAffine) { final WarpAffine wa = (WarpAffine) warp; return wa.getTransform(); } else { throw new TransformException("Wrap transform is not affine."); } } else { throw new TransformException("Geopositioning type unknowned."); } } /** * Read the raster dimension from the document. This include number of rows, * columns and bands. * Those informations are provided by the Raster_dimensions tag. * * @param doc * @return int[] 0:rows, 1:cols, 2:bands */ public static int[] readRasterDimension(final Element doc) { final Element ele = firstElement(doc, TAG_RASTER_DIMENSIONS); final int rows = textValueSafe(ele, TAG_NROWS, Integer.class); final int cols = textValueSafe(ele, TAG_NCOLS, Integer.class); final int bands = textValueSafe(ele, TAG_NBANDS, Integer.class); return new int[]{rows, cols, bands}; } /** * Read the number of bits used for each pixel of each band of the raster image. * * @param doc * @return int the number of bits */ public static int readNBits(final Element doc) { final Element nodeEncoding = firstElement(doc, TAG_RASTER_ENCODING); return textValueSafe(nodeEncoding, TAG_NBITS, Integer.class); } /** * Read the coverage sample dimensions. * Those informations are provided by the Image_display tag. * * @param parent * @return GridSampleDimension */ public static int[] readColorBandMapping(final Element parent) { final Element ele = firstElement(parent, TAG_IMAGE_DISPLAY); if (ele == null) { return null; } final Element displayOrder = firstElement(ele, TAG_BAND_DISPLAY_ORDER); if (displayOrder == null) { return null; } //those parameters are mandatory final int red = textValueSafe(displayOrder, TAG_RED_CHANNEL, Integer.class); final int green = textValueSafe(displayOrder, TAG_GREEN_CHANNEL, Integer.class); final int blue = textValueSafe(displayOrder, TAG_BLUE_CHANNEL, Integer.class); return new int[]{red - 1, green - 1, blue - 1}; } /** * Read the coverage sample dimensions. * Those informations are provided by dimap tags : * - Image_Interpretation for description and sample to geophysic. * - Image_display for special values. * - Raster_Encoding for sample model bytes encoding * * @param doc * @return GridSampleDimension */ public static GridSampleDimension[] readSampleDimensions(final Element doc) { // read raster encoding informations ----------------------------------- final Element nodeEncoding = firstElement(doc, TAG_RASTER_ENCODING); final int nbits = textValueSafe(nodeEncoding, TAG_NBITS, Integer.class); final String byteOrder = textValueSafe(nodeEncoding, TAG_BYTEORDER, String.class); final String dataType = textValueSafe(nodeEncoding, TAG_DATA_TYPE, String.class); final Integer skip = textValueSafe(nodeEncoding, TAG_SKIP_BYTES, Integer.class); final String layout = textValueSafe(nodeEncoding, TAG_BANDS_LAYOUT, String.class); final SampleDimensionType dimensionType = TypeMap.getSampleDimensionType(DataType.valueOf(dataType).getNumberSet(), nbits); // read special values ------------------------------------------------- final Element nodeDisplay = firstElement(doc, TAG_IMAGE_DISPLAY); final Element nodeBandOrder = firstElement(nodeDisplay, TAG_BAND_DISPLAY_ORDER); final Integer red = textValueSafe(nodeBandOrder, TAG_RED_CHANNEL, Integer.class); final Integer green = textValueSafe(nodeBandOrder, TAG_GREEN_CHANNEL, Integer.class); final Integer blue = textValueSafe(nodeBandOrder, TAG_BLUE_CHANNEL, Integer.class); // special values final Map<String, Integer> specialValues = new HashMap<>(); final NodeList nodeSpecialValues = nodeDisplay.getElementsByTagName(TAG_SPECIAL_VALUE); for (int i = 0; i < nodeSpecialValues.getLength(); i++) { final Element nodeSpecialValue = (Element) nodeSpecialValues.item(i); final Integer valueIndex = textValueSafe(nodeSpecialValue, TAG_SPECIAL_VALUE_INDEX, Integer.class); final String valueText = textValueSafe(nodeSpecialValue, TAG_SPECIAL_VALUE_TEXT, String.class); specialValues.put(valueText, valueIndex); } // read band statistics ------------------------------------------------ final NodeList nodeStats = nodeDisplay.getElementsByTagName(TAG_BAND_STATISTICS); final Map<Integer, NumberRange> valueRanges = new HashMap<>(); for (int i = 0, n = nodeStats.getLength(); i < n; i++) { final Element bandStat = (Element) nodeStats.item(i); final double stxMin = textValueSafe(bandStat, TAG_STX_MIN, Double.class); final double stxMax = textValueSafe(bandStat, TAG_STX_MAX, Double.class); final double stxMean = textValueSafe(bandStat, TAG_STX_MEAN, Double.class); final double stxStdv = textValueSafe(bandStat, TAG_STX_STDV, Double.class); final double stxLinMin = textValueSafe(bandStat, TAG_STX_LIN_MIN, Double.class); final double stxLinMax = textValueSafe(bandStat, TAG_STX_LIN_MAX, Double.class); final int bandIndex = textValueSafe(bandStat, TAG_BAND_INDEX, Integer.class); valueRanges.put(bandIndex, NumberRange.create(stxMin, true, stxMax, true)); } // read dimensions ----------------------------------------------------- final Element nodeInterpretation = firstElement(doc, TAG_IMAGE_INTERPRETATION); final NodeList spectrals = nodeInterpretation.getElementsByTagName(TAG_SPECTRAL_BAND_INFO); final Map<Integer, GridSampleDimension> dimensions = new HashMap<>(); for (int i = 0, n = spectrals.getLength(); i < n; i++) { final Element spectre = (Element) spectrals.item(i); /* This record provides the unit of the physical value resulting from data radiometric count to physical measure conversion such as Illumination or height : L = X/A + B - L is the resulting physical value expressed in PHYSICAL_UNIT - X is the radiometric value at a given pixel location as stored in the raster file (unitless). - A is the gain (PHYSICAL_GAIN) - B is the bias (PHYSICAL_BIAS) */ final int bandIndex = textValueSafe(spectre, TAG_BAND_INDEX, Integer.class); final String bandDesc = textValueSafe(spectre, TAG_BAND_DESCRIPTION, String.class); final String physicUnit = textValueSafe(spectre, TAG_PHYSICAL_UNIT, String.class); final double physicGain = textValueSafe(spectre, TAG_PHYSICAL_GAIN, Double.class); final double physicBias = textValueSafe(spectre, TAG_PHYSICAL_BIAS, Double.class); Unit unit = null; try { Units.valueOf(physicUnit.trim()); } catch (Exception ex) { //catch anything, this doesn't always throw parse exception unit = Units.UNITY; } //transform sample to geophysics final TransferFunction f = new TransferFunction(); f.setType(TransferFunctionType.LINEAR); f.setScale(1 / physicGain); f.setOffset(physicBias); final MathTransform1D sampleToGeo = f.getTransform(); List<Category> cats = new ArrayList<>(); NumberRange range = valueRanges.get(bandIndex); if (range != null) { //range is in geophysic values, can not use it, todo convert it. } else { range = getThreshold(doc, bandIndex); } if (range == null) { range = new NumberRange(Integer.class, Integer.MIN_VALUE, true, Integer.MAX_VALUE, true); } double min = range.getMinDouble(); double max = range.getMaxDouble(); for (Map.Entry<String, Integer> entry : specialValues.entrySet()) { cats.add(new Category(entry.getKey(), new Color(0,0,0,0), entry.getValue())); if (entry.getValue().doubleValue() == min) { min++; } else if (entry.getValue().doubleValue() == max) { max--; } } range = new NumberRange(Double.class, min, true, max, true); cats.add(new Category("data", null, range, sampleToGeo)); final GridSampleDimension dim = new GridSampleDimension(bandDesc, cats.toArray(new Category[cats.size()]), unit); dimensions.put(bandIndex, dim); } final GridSampleDimension[] dims = new GridSampleDimension[dimensions.size()]; for (int i = 0; i < dimensions.size(); i++) { GridSampleDimension dim = dimensions.get(i + 1); if (dim == null) { //no information on this band, create an empty one dim = new GridSampleDimension(String.valueOf(i + 1)); } dims[i] = dim; } return dims; } private static NumberRange getThreshold(Element doc, int bandIndex) { final Element nodeDataProcessing = firstElement(doc, TAG_DATA_PROCESSING); final Element processingOptions = firstElement(nodeDataProcessing, TAG_PROCESSING_OPTIONS); final Element dynamicStrech = firstElement(processingOptions, TAG_DYNAMIC_STRETCH); final NodeList thresholds = dynamicStrech.getElementsByTagName(TAG_THRESHOLDS); for (int i = 0; i < thresholds.getLength(); i++) { final Element threshold = (Element) thresholds.item(i); final int idx = textValueSafe(threshold, TAG_BAND_INDEX, Integer.class); if (idx == bandIndex) { final double low = textValueSafe(threshold, TAG_LOW_THRESHOLD, Double.class); final double high = textValueSafe(threshold, TAG_HIGH_THRESHOLD, Double.class); return new NumberRange(Double.class, low, true, high, true); } } return null; } /** * @return Dataset Name from Dataset_ID tag. */ public static String readDatasetName(final Element doc) { final Element datasetID = firstElement(doc, TAG_DATASET_ID); final String name = textValueSafe(datasetID, TAG_DATASET_NAME, String.class); return name; } /** * @return Dataset orthorectified envelope from Dataset_Frame tag. */ public static Geometry readDatasetVertex(final Element doc) throws NoSuchAuthorityCodeException, FactoryException { final Element datasetFrame = firstElement(doc, TAG_DATASET_FRAME); final List<Element> vertexs = getListElements(datasetFrame, TAG_VERTEX); final CoordinateReferenceSystem crs = readCRS(doc); final GeometryFactory geometryFact = new JTSGeometryFactory(crs); final int len = vertexs.size(); final DirectPosition[] exteriorRing = new DirectPosition[len + 1]; DirectPosition first = null; for (int i = 0; i < len; i++) { final Element vertex = vertexs.get(i); final Double lon = textValueSafe(vertex, TAG_FRAME_LON, Double.class); final Double lat = textValueSafe(vertex, TAG_FRAME_LAT, Double.class); final double[] coords = new double[2]; coords[0] = lon; coords[1] = lat; final DirectPosition position = geometryFact.createDirectPosition(coords); exteriorRing[i] = position; if (i == 0) { first = position; } } if (first != null) { exteriorRing[len] = first; } return (Geometry) GeometryUtils.createPolygon(exteriorRing); } /** * @return DatasetThumbnail from Dataset_ID tag. */ public static String readDatasetThumbnail(final Element doc) { final Element datasetID = firstElement(doc, TAG_DATASET_ID); final String name = textAttributeValueSafe(datasetID, TAG_DATASET_TN_PATH, ATTRIBUTE_HREF, String.class); return name.toLowerCase(); } /** * @return DatasetQuickLook from Dataset_ID tag. */ public static String readDatasetQuickLook(final Element doc) { final Element datasetID = firstElement(doc, TAG_DATASET_ID); final String name = textAttributeValueSafe(datasetID, TAG_DATASET_QL_PATH, ATTRIBUTE_HREF, String.class); return name.toLowerCase(); } /** * Return the TypeProduct according the missionIndex and the sensorCode * @param missionIndex * @param sensorCode * @return */ public static String findTypeProduct(final int missionIndex, final String sensorCode) { if ((missionIndex == 2 && "P".equals(sensorCode)) || (missionIndex == 4 && "M".equals(sensorCode)) || (missionIndex == 5 && "A".equals(sensorCode)) || (missionIndex == 5 && "B".equals(sensorCode))) return "Black and White"; if ((missionIndex == 2 && "X".equals(sensorCode)) || (missionIndex == 4 && "X".equals(sensorCode)) || (missionIndex == 5 && "X".equals(sensorCode))) return "Color"; if ((missionIndex == 4 && "I".equals(sensorCode)) || (missionIndex == 5 && "J".equals(sensorCode))) return "Color with SWIR"; if (missionIndex == 5 && "T".equals(sensorCode)) return "Black White or Color"; return null; } /** * Return the Resolution according the missionIndex and the sensorCode * @param missionIndex * @param sensorCode * @return */ public static Double findResolution(final int missionIndex, final String sensorCode) { if ((missionIndex == 2 && "P".equals(sensorCode)) || (missionIndex == 4 && "M".equals(sensorCode)) || (missionIndex == 5 && "X".equals(sensorCode)) || (missionIndex == 5 && "J".equals(sensorCode))) return 10.0; if ((missionIndex == 2 && "X".equals(sensorCode)) || (missionIndex == 4 && "I".equals(sensorCode)) || (missionIndex == 4 && "X".equals(sensorCode))) return 20.0; if ((missionIndex == 5 && "A".equals(sensorCode)) || (missionIndex == 5 && "B".equals(sensorCode))) return 5.0; if (missionIndex == 5 && "T".equals(sensorCode)) return 2.5; return null; } /** * Converts the given dimap document in a metadata object. * Since there is no one to one relation between ISO 19115 and Dimap, * the returned metadata is a best effort relation. * * @param doc * @param metadata : metadata to fill, if null it will create one. * @return Metadata, never null */ public static DefaultMetadata fillMetadata(final Element doc, DefaultMetadata metadata) throws IOException { if (metadata == null) { metadata = new DefaultMetadata(); } else { //To ensure we don't modify the original if (metadata instanceof MI_Metadata) { metadata = new MI_Metadata(metadata); } else { metadata = new DefaultMetadata(metadata); } } String thumbnail = null; String name = null; //Dimap_Document STRUCTURE // //<Metadata_Id/> - Mandatory //<Dataset_Id/> - Mandatory //<Dataset_Frame/> - Optional //<Coordinate_Reference_System/> - Mandatory //<Raster_CS/> - Mandatory //<Geoposition/> - Mandatory //<Production/> - Mandatory //<Quality_Assessment/> - Optional //<Raster_Dimensions/> - Mandatory //<Raster_Encoding/> - Mandatory //<Data_Processing/> - Mandatory //<Data_Access/> - Mandatory //<Image_Display/> - Mandatory //<Image_Interpretation/> - Mandatory //<Dataset_Sources/> - Mandatory //<Data_Strip/> - Mandatory //Default values metadata.setCharacterSets(Collections.singleton(StandardCharsets.UTF_8)); metadata.setLanguage(Locale.ENGLISH); metadata.setDateStamp(new Date()); //<xsd:element minOccurs="1" maxOccurs="1" ref="Dataset_Id"/> ---------- final Element datasetID = firstElement(doc, TAG_DATASET_ID); if (datasetID != null) { //MAPPING // //<DATASET_NAME/> → used to build : MetaData.fileIdentifier //<DATASET_TN_PATH/> → ? //<DATASET_TN_FORMAT/> → ? //<DATASET_QL_PATH/> → ? //<DATASET_QL_FORMAT/> → ? //<COPYRIGHT/> → MetaData.metadataConstraints > LegalConstraints.otherConstraints // → MetaData.identificationInfo > resourcesConstraints > LegalConstraints.otherConstraints final String copyright = textValueSafe(datasetID, TAG_DATASET_COPYRIGHT, String.class); thumbnail = textAttributeValueSafe(datasetID, TAG_DATASET_TN_PATH, ATTRIBUTE_HREF, String.class); name = textValueSafe(datasetID, TAG_DATASET_NAME, String.class); //MetaData > FileIdentifier metadata.setFileIdentifier(name.replaceAll(":", "_").replaceAll(" ", "_").replaceAll("/", "_")); //MetaData > MetadataConstraints final Restriction restriction = Restriction.COPYRIGHT; final DefaultLegalConstraints constraints = new DefaultLegalConstraints(); constraints.setUseConstraints(Collections.singleton(restriction)); constraints.setOtherConstraints(Collections.singleton(new SimpleInternationalString(copyright))); metadata.getMetadataConstraints().add(constraints); // duplicate ? final AbstractIdentification identification = getIdentificationInfo(metadata); identification.getResourceConstraints().add(constraints); } //<xsd:element minOccurs="0" maxOccurs="1" ref="Dataset_Frame"/> ------- //Has been set from the geotiff informations final Element datasetFrame = firstElement(doc, TAG_DATASET_FRAME); if (datasetFrame != null) { //MAPPING // //SCENE_ORIENTATION → ? //<Vertex> Occurs : 3 to 8 // <FRAME_LON/> → used to build : MetaData.identificationInfo > DataIdentification.extents > Extents.geographicElements > BoundingPolygon // <FRAME_LAT/> → used to build : MetaData.identificationInfo > DataIdentification.extents > Extents.geographicElements > BoundingPolygon // <FRAME_ROW/> → ? // <FRAME_COL/> → ? // <FRAME_X/> → ? // <FRAME_Y/> → ? //</Vertex> //... //<Scene_Center> Occurs : 1 to 1 // <FRAME_LON/> → ? // <FRAME_LAT/> → ? // <FRAME_ROW/> → ? // <FRAME_COL/> → ? //</Scene_Center> //<SCENE_ORIENTATION/> → ? // if (metadata instanceof MI_Metadata) { Geometry geometry = null; try { geometry = readDatasetVertex(doc); } catch (NoSuchAuthorityCodeException ex) { throw new IOException("Exception when creating the bounding geometry : ", ex); } catch (FactoryException ex) { throw new IOException("Exception when creating the bounding geometry : ", ex); } /** * Fills IdentificationInfo */ //MetaData > DataIdentification > Extent > BoundingPolygon if (geometry != null) { final DefaultBoundingPolygon boundingPolygon = new DefaultBoundingPolygon(); boundingPolygon.setPolygons(Collections.singleton(geometry)); final DefaultGeographicDescription geographicDesc = new DefaultGeographicDescription(); //not safe final Element gridReference = firstElement(doc, TAG_SCENE_GRID_REFERENCE); final String geographicId; if (gridReference != null) { final String rawGeoId = gridReference.getTextContent(); geographicId = rawGeoId.substring(0, 3) + "-" + rawGeoId.substring(3); } else { final String[] fileIdSplited = metadata.getFileIdentifier().split("-"); geographicId = fileIdSplited[0].substring(fileIdSplited[0].length() - 3) + "-" + fileIdSplited[1].substring(0, 3); } geographicDesc.setGeographicIdentifier(new DefaultIdentifier(geographicId)); final DefaultExtent extent = getExtent(metadata); extent.getGeographicElements().add(boundingPolygon); extent.getGeographicElements().add(geographicDesc); } } } //<xsd:element minOccurs="1" maxOccurs="1" ref="Production"/> --------- //Can be changed in a Responsible party information final Element production = firstElement(doc, TAG_PRODUCTION); if (production != null) { //MAPPING // //<DATASET_PRODUCER_NAME/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.processors > ResponsibleParty.organisationName //<DATASET_PRODUCER_URL/> → ? //<DATASET_PRODUCTION_DATE/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.date //<PRODUCT_TYPE/> → ? //<PRODUCT_INFO/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.description //<JOB_ID/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep > Processing.identifier > Identifier.code //<Production_Facility> Occurs : 1 to 1 // <SOFTWARE_NAME/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.processingInfo > Processing.softwareReference > Citation.title // <SOFTWARE_VERSION/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.processingInfo > Processing.softwareReference > Citation.edition // <PROCESSING_CENTER/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.processingInfo > Processing.softwareReference > Citation.citedResponsibleParties > ResponsibleParty.organisationName //</Production_Facility> final String jobId = textValueSafe(production, TAG_JOB_ID, String.class); final String productType = textValueSafe(production, TAG_PRODUCT_TYPE, String.class); final String productInfo = textValueSafe(production, TAG_PRODUCT_INFO, String.class); final String producerName = textValueSafe(production, TAG_DATASET_PRODUCER_NAME, String.class); final Date productionDate = textValueSafe(production, TAG_DATASET_PRODUCTION_DATE, Date.class); final Element producerEle = firstElement(production, TAG_DATASET_PRODUCER_URL); URI producerURL = null; try { producerURL = new URI(producerEle.getAttribute(ATT_HREF)); } catch (URISyntaxException ex) { LOGGER.log(Level.WARNING, ex.getLocalizedMessage(), ex); } final Element facility = firstElement(production, TAG_PRODUCTION_FACILITY); /** * Fills DataQualityInfo */ //MetaData > DataQuality > Lineage > ProcessStep final DefaultResponsibleParty responsibleParty = new DefaultResponsibleParty(Role.ORIGINATOR); responsibleParty.setOrganisationName(new SimpleInternationalString(producerName)); final DefaultProcessStep processStep = getProcessStep(metadata); processStep.setDescription(new SimpleInternationalString(productInfo)); processStep.setDate(productionDate); processStep.getProcessors().add(responsibleParty); //MetaData > DataQuality > Lineage > ProcessStep > Processing > Identifier if (jobId != null) { final DefaultProcessing processing = getProcessingInfo(metadata); processing.setIdentifier(new DefaultIdentifier(jobId)); } //MetaData > DataQuality > Lineage > ProcessStep > Processing > SoftwareReferences if (facility != null) { final String softwareName = textValueSafe(facility, TAG_PRODUCTION_FACILITY_SOFTWARE_NAME, String.class); final String softwareVersion = textValueSafe(facility, TAG_PRODUCTION_FACILITY_SOFTWARE_VERSION, String.class); final String productionCenter = textValueSafe(facility, TAG_PRODUCTION_FACILITY_PROCESSING_CENTER, String.class); final DefaultCitation softCitation = new DefaultCitation(); softCitation.setTitle(new SimpleInternationalString(softwareName)); softCitation.setEdition(new SimpleInternationalString(softwareVersion)); if (productionCenter != null) { final DefaultResponsibleParty softResponsibleParty = new DefaultResponsibleParty(); softResponsibleParty.setOrganisationName(new SimpleInternationalString(productionCenter)); softCitation.getCitedResponsibleParties().add(softResponsibleParty); } final DefaultProcessing processing = getProcessingInfo(metadata); processing.getSoftwareReferences().add(softCitation); } } //<xsd:element minOccurs="1" maxOccurs="1" ref="Raster_Dimensions"/> -- //Has been set from the geotiff informations final Element rasterDim = firstElement(doc, TAG_RASTER_DIMENSIONS); if (rasterDim != null) { //MAPPING // //<NCOLS/> → MetaData.spatialRepresentationInfo > GridSpatialRepresentation.axisDimensionProperties > Dimension.dimensionSize //<NROWS/> → MetaData.spatialRepresentationInfo > GridSpatialRepresentation.axisDimensionProperties > Dimension.dimensionSize //<NBANDS/> → ? final Integer ncols = textValueSafe(rasterDim, TAG_NCOLS, Integer.class); final Integer nrows = textValueSafe(rasterDim, TAG_NROWS, Integer.class); /** * Fills SpatialRepresentationInfo */ //MetaData > GridSpatialRepresentation > Dimension final DefaultDimension rowDim = new DefaultDimension(); rowDim.setDimensionSize(nrows); rowDim.setDimensionName(DimensionNameType.ROW); final DefaultDimension columnDim = new DefaultDimension(); columnDim.setDimensionSize(ncols); columnDim.setDimensionName(DimensionNameType.COLUMN); final DefaultGridSpatialRepresentation gridSpacialRepr = (DefaultGridSpatialRepresentation) getSpatialRepresentationInfo(metadata); final List<Dimension> axisDimensions = gridSpacialRepr.getAxisDimensionProperties(); axisDimensions.add(rowDim); axisDimensions.add(columnDim); } //<xsd:element minOccurs="1" maxOccurs="1" ref="Data_Processing"/> ---- final Element dataProcessing = firstElement(doc, TAG_DATA_PROCESSING); if (dataProcessing != null) { //MAPPING // //<PROCESSING_LEVEL/> → ? //<GEOMETRIC_PROCESSING/> → ? //<RADIOMETRIC_PROCESSING/> → ? //<SPECTRAL_PROCESSING/> → ? //<Processing_Options> Occurs : 1 to 1 // <MEAN_RECTIFICATION_ELEVATION/> → ? // <LINE_SHIFT/> → ? // <DECOMPRESSION_TYPE/> → ? // <SWIR_BAND_REGISTRATION_FLAG/> → ? // <X_BANDS_REGISTRATION_FLAG/> → ? // <RESAMPLING_METHOD/> → ? // <Dynamic_Stretch> Occurs : 0 to 1 // <Thresholds> Occurs : 1 to n // <BAND_INDEX/> → MetaData.contentInfo > ImageDescription.dimensions > Band.descriptor // <LOW_THRESHOLD/> → MetaData.contentInfo > ImageDescription.dimensions > Band.minValue // <HIGH_THRESHOLD/> → MetaData.contentInfo > ImageDescription.dimensions > Band.maxValue // </Thresholds> // <Dynamic_Stretch> // <Deconvolution> Occurs : 0 to 1 // <LINE_SHIFT/> → ? // <DECOMPRESSION_TYPE/> → ? // <Deconvolution> // <Sampling_Step> Occurs : 0 to 1 // <SAMPLING_STEP_X/> → ? // <SAMPLING_STEP_Y/> → ? // <Sampling_Step> // <SuperMode_Processing> Occurs : 0 to 1 // <SM_CORRELATION_NEEDED/> → ? // <SM_RAW_GRID_FILTERING/> → ? // <SM_PROCESSING_TYPE/> → ? // <SuperMode_Processing> // <Correction_Algorithm> Occurs : 0 to n // <ALGORITHM_TYPE/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.processingInfo > Processing.algorithms > Algorithm.description // <ALGORITHM_NAME/> → MetaData.dataQualityInfo > DataQuality.lineage > Lineage.processSteps > ProcessStep.processingInfo > Processing.algorithms > Algorithm.citation > Citation.title // <ALGORITHM_ACTIVATION/> → ? // <Correction_Algorithm> // ... //</Processing_Options> //<Regions_Of_Interest> Occurs : 0 to 1 // <Region_Of_Interest> Occurs : 1 to n // <COL_MIN/> → ? // <ROW_MIN/> → ? // <COL_MAX/> → ? // <ROW_MAX/> → ? // </Region_Of_Interest> // ... //</Regions_Of_Interest> final String algoType = textValueSafe(dataProcessing, TAG_DATA_PROCESSING_ALGORITHM_TYPE, String.class); final String algoName = textValueSafe(dataProcessing, TAG_DATA_PROCESSING_ALGORITHM_NAME, String.class); final String processingLevel = textValueSafe(dataProcessing, TAG_DATA_PROCESSING_PROCESSING_LEVEL, String.class); /** * Fills DataQualityInfo */ //MetaData > DataQuality > Lineage > ProcessStep > Processing > Algorithm if (algoName != null && algoType != null) { final DefaultCitation citation = new DefaultCitation(); citation.setTitle(new SimpleInternationalString(algoName)); final DefaultAlgorithm algorithm = new DefaultAlgorithm(); algorithm.setDescription(new SimpleInternationalString(algoType)); algorithm.setCitation(citation); final DefaultProcessing processing = getProcessingInfo(metadata); processing.getAlgorithms().add(algorithm); } /** * Fills ContentInfo */ //MetaData > ImageDescription > Dimension final Element processingOpts = firstElement(dataProcessing, TAG_PROCESSING_OPTIONS); if (processingOpts != null) { final Element dynamicStretch = firstElement(dataProcessing, TAG_DYNAMIC_STRETCH); if (dynamicStretch != null) { final List<Element> thresholds = getListElements(dynamicStretch, TAG_THRESHOLDS); for (int i = 0, len = thresholds.size(); i < len; i++) { final Element threshold = (Element) thresholds.get(i); final int bandIndex = textValueSafe(threshold, TAG_BAND_INDEX, Integer.class); final Double lowThreshold = textValueSafe(threshold, TAG_LOW_THRESHOLD, Double.class); final Double highThreshold = textValueSafe(threshold, TAG_HIGH_THRESHOLD, Double.class); final DefaultNameFactory factory = new DefaultNameFactory(); final TypeName tname = factory.createTypeName(null, "BAND_INDEX"); final MemberName memberName = factory.createMemberName(null, String.valueOf(bandIndex), tname); final DefaultBand dimension = getBandDimension(metadata, bandIndex); dimension.setMinValue(lowThreshold); dimension.setMaxValue(highThreshold); dimension.setSequenceIdentifier(memberName); } } } //MetaData > ContentInfo (ImageDescription) > ProcessingLevelCode if (processingLevel != null) { final DefaultImageDescription contentInfo = (DefaultImageDescription) getContentInfo(metadata); contentInfo.setProcessingLevelCode(new DefaultIdentifier(processingLevel)); } } //<xsd:element minOccurs="1" maxOccurs="1" ref="Data_Access"/> -------- final Element dataAccess = firstElement(doc, TAG_DATA_ACCESS); if (dataAccess != null) { //MAPPING // //<DATA_FILE_FORMAT/> → Metadata.identificationInfo > DataIdentification.resourceFormats > Format.name and Format.version //<DATA_FILE_FORMAT_DESC/> → ? //<DATA_FILE_ORGANISATION/> → ? //<Data_File> Occurs : 1 to 1 // <DATA_FILE_PATH/> → ? //</Data_File> final Element formatTag = firstElement(dataAccess, TAG_DATA_FILE_FORMAT); /** * Fills IdentificationInfo */ //MetaData > DataIdentification > Format if (formatTag != null) { final String version = formatTag.getAttribute(ATT_VERSION); final String formatName = formatTag.getTextContent(); final DefaultFormat format = new DefaultFormat(); format.setName(new SimpleInternationalString(formatName)); format.setVersion(new SimpleInternationalString(version)); final AbstractIdentification idf = getIdentificationInfo(metadata); idf.getResourceFormats().add(format); } } //<xsd:element minOccurs="1" maxOccurs="1" ref="Image_Interpretation"/> final Element imageInter = firstElement(doc, TAG_IMAGE_INTERPRETATION); if (imageInter != null) { //MAPPING // //<Spectral_Band_Info> Occurs : 1 to n // <BAND_INDEX/> → MetaData.contentInfo > ImageDescription.dimensions > Band.descriptor // <BAND_DESCRIPTION/> → MetaData.contentInfo > ImageDescription.dimensions > Band.descriptor // <PHYSICAL_UNIT/> → MetaData.contentInfo > ImageDescription.dimensions > Band.Units // <PHYSICAL_GAIN/> → MetaData.contentInfo > ImageDescription.dimensions > Band.scaleFactor // <PHYSICAL_BIAS/> → MetaData.contentInfo > ImageDescription.dimensions > Band.offset // <PHYSICAL_CALIBRATION_DATE/> → ? //</Spectral_Band_Info> //... /** * Fills ContentInfo */ final List<Element> spectrals = getListElements(imageInter, TAG_SPECTRAL_BAND_INFO); if (spectrals != null) { final Element physicalUnitElem = firstElement(imageInter, TAG_PHYSICAL_UNIT); final int nbits = readNBits(doc); //MetaData > ImageDescription > RecordType //if (physicalUnitElem != null) { // TODO: how to build an attribute description // final RecordType recordType = new DefaultRecordType(); // // final DefaultImageDescription contentInfo = (DefaultImageDescription) getContentInfo(metadata); // contentInfo.setAttributeDescription(null); //} //MetaData > ImageDescription > Dimensions for (int i = 0, len = spectrals.size(); i < len; i++) { final Element spectre = (Element) spectrals.get(i); final int bandIndex = textValueSafe(spectre, TAG_BAND_INDEX, Integer.class); final String bandDesc = textValueSafe(spectre, TAG_BAND_DESCRIPTION, String.class); final Double physicalGain = textValueSafe(spectre, TAG_PHYSICAL_GAIN, Double.class); final Double physicalBias = textValueSafe(spectre, TAG_PHYSICAL_BIAS, Double.class); String physicalUnit = textValueSafe(spectre, TAG_PHYSICAL_UNIT, String.class); physicalUnit = physicalUnit.substring(physicalUnit.indexOf("(") + 1, physicalUnit.indexOf(")")); //final Unit unit = Units.valueOf(physicalUnit); final DefaultBand dimension = getBandDimension(metadata, bandIndex); dimension.setBitsPerValue(nbits); dimension.setDescriptor(new SimpleInternationalString(bandDesc)); dimension.setScaleFactor(1 / physicalGain); dimension.setOffset(physicalBias); //dimension.setUnits(unit); } } } //<xsd:element minOccurs="1" maxOccurs="1" ref="Dataset_Sources"/> ----- //Could be mapped to Aquisition informations final Element datasetSources = firstElement(doc, TAG_DATASET_SOURCES); if (datasetSources != null) { //MAPPING // //<Source_Information> Occurs : 1 to 3 // <SOURCE_ID/> → ? // <SOURCE_TYPE/> → ? // <SOURCE_DESCRIPTION/> → Metadata.identificationInfo > DataIdentification.abstract // <Source_Frame> Occurs : 0 to 1 // <Vertex> Occurs : 4 to 4 // <FRAME_LON/> → ? // <FRAME_LAT/> → ? // <FRAME_ROW/> → ? // <FRAME_COL/> → ? // <FRAME_X/> → ? // <FRAME_Y/> → ? // </Vertex> // ... // </Source_Frame> // <Scene_Source> Occurs : 0 to 1 // <MISSION/> → MetaData.acquisitionInformation > AcquisitionInformation.operations > Operations.description // AND MetaData.acquisitionInformation > AcquisitionInformation.plateforms > Platform.identifier > Identifier.code // AND MetaData.acquisitionInformation > AcquisitionInformation.plateforms > Platform.Citation > Citation.title // AND MetaData.acquisitionInformation > AcquisitionInformation.plateforms > Platform.description // AND Metadata.identificationInfo > DataIdentification.abstract // AND Metadata.identificationInfo > DataIdentification.citation > Citation.title // // <MISSION_INDEX/> → MetaData.acquisitionInformation > AcquisitionInformation.operations > Operations.identifier > Identifier.code // AND MetaData.acquisitionInformation > AcquisitionInformation.plateforms > Platform.identifier > Identifier.code // AND MetaData.acquisitionInformation > AcquisitionInformation.plateforms > Platform.description // AND Metadata.identificationInfo > DataIdentification.abstract // AND Metadata.identificationInfo > DataIdentification.citation > Citation.title // AND Metadata.identificationInfo > DataIdentification.spatialResolutions > Resolution.distance // // <INSTRUMENT/> → MetaData.acquisitionInformation > AcquisitionInformation.instruments > Instrument.description // <INSTRUMENT_INDEX/> → MetaData.acquisitionInformation > AcquisitionInformation.instruments > Instrument.identifier > Identifier.code // <SENSOR_CODE/> → Metadata.identificationInfo > DataIdentification.abstract // AND Metadata.identificationInfo > DataIdentification.resolution > Resolution. // // <IMAGING_DATE/> → MetaData.identificationInfo > DataIdentification.citation > Citation.dates > CitationDate // <IMAGING_TIME/> → MetaData.identificationInfo > DataIdentification.citation > Citation.dates > CitationDate // <GRID_REFERENCE/> → ? // <SHIFT_VALUE/> → ? // <INCIDENCE_ANGLE/> → ? // <THEORETICAL_RESOLUTION/> → ? // <SUN_AZIMUTH/> → MetaData.contentInfo > ImageDescription.processingLevelCode > Identifier.code // <SUN_ELEVATION/> → MetaData.contentInfo > ImageDescription.illuminationAzimuthAngle // <SCENE_PROCESSING_LEVEL/> → MetaData.contentInfo > ImageDescription.illuminationElevationAngle // <VIEWING_ANGLE/> → ? // <Imaging_Parameters> Occurs : 1 to 1 // <REVOLUTION_NUMBER/> → ? // <COMPRESSION_MODE/> → ? // <DIRECT_PLAYBACK_INDICATOR/> → ? // <REFOCUSING_STEP_NUM/> → ? // <COUPLED_MODE_FLAG/> → ? // <SWATH_MODE/> → ? // </Imaging_Parameters> // </Scene_Source> // <Quality_Assessment> Occurs : 0 to 1 // <QUALITY_TABLES/> → ? // <Quality_Parameter> Occurs : 1 to n // <QUALITY_PARAMETER_CODE/> → ? // <QUALITY_PARAMETER_DESC/> → ? // <QUALITY_PARAMETER_VALUE/> → ? // </Quality_Parameter> // </Quality_Assessment> //</Source_Information> //... final Element sourceInfo = firstElement(datasetSources, TAG_SOURCE_INFORMATION); if (sourceInfo != null) { final String sourceDesc = textValueSafe(sourceInfo, TAG_SOURCE_DESCRIPTION, String.class); final String sourceType = textValueSafe(sourceInfo, TAG_SOURCE_TYPE, String.class); /** * Fills IdentificationInfo, AcquisitionInfo and ContentInfo */ final Element sceneSource = firstElement(sourceInfo, TAG_SCENE_SOURCE); if (sceneSource != null) { final String imagingDate = textValueSafe(sceneSource, TAG_SCENE_IMAGING_DATE, String.class); final String imagingTime = textValueSafe(sceneSource, TAG_SCENE_IMAGING_TIME, String.class); final String missionName = textValueSafe(sceneSource, TAG_SCENE_MISSION, String.class); final int missionIndex = textValueSafe(sceneSource, TAG_SCENE_MISSION_INDEX, Integer.class); final String instrumentName = textValueSafe(sceneSource, TAG_SCENE_INSTRUMENT, String.class); final int instrumentIndex = textValueSafe(sceneSource, TAG_SCENE_INSTRUMENT_INDEX, Integer.class); final String sensorCode = textValueSafe(sceneSource, TAG_SCENE_SENSOR_CODE, String.class); final Double incidenceAngle = textValueSafe(sceneSource, TAG_SCENE_INCIDENCE_ANGLE, Double.class); final Double theoreticalResolution = textValueSafe(sceneSource, TAG_SCENE_THEORETICAL_RESOLUTION, Double.class); final String viewingAngle = textValueSafe(sceneSource, TAG_SCENE_VIEWING_ANGLE, String.class); final Double sunAzimuth = textValueSafe(sceneSource, TAG_SCENE_SUN_AZIMUTH, Double.class); final Double sunElevation = textValueSafe(sceneSource, TAG_SCENE_SUN_ELEVATION, Double.class); /** * Fills IdentificationInfo */ //MetaData > IdentificationInfo (DataIdentification) > GraphicOverviews final DefaultDataIdentification dataIdentification = (DefaultDataIdentification) getIdentificationInfo(metadata); if (thumbnail != null && thumbnail.contains(".")) { dataIdentification.getGraphicOverviews().add(new DefaultBrowseGraphic( generateFileName(name, thumbnail.substring(thumbnail.lastIndexOf("."))))); } // MetaData > IdentificationInfo (DataIdentification) > supplementalInformation if (incidenceAngle != null) { dataIdentification.setSupplementalInformation(new SimpleInternationalString(("incidence angle :" + incidenceAngle))); } //MetaData > IdentificationInfo (DataIdentification) > Abstract dataIdentification.setAbstract(new SimpleInternationalString( missionName + " " + missionIndex + " " + sourceDesc)); //MetaData > IdentificationInfo (DataIdentification) > Citation final DefaultCitation citation = new DefaultCitation(); final ISODateParser dateParser = new ISODateParser(); final Date date = dateParser.parseToDate(imagingDate + "T" + imagingTime); citation.setDates(Collections.singleton(new DefaultCitationDate(date, DateType.CREATION))); citation.setTitle(new SimpleInternationalString( missionName + " " + missionIndex + " " + sourceType + " " + findTypeProduct(missionIndex, sensorCode))); dataIdentification.setCitation(citation); //MetaData > IdentificationInfo (DataIdentification) > Resolution final DefaultResolution resolution = new DefaultResolution(); resolution.setDistance(findResolution(missionIndex, sensorCode)); dataIdentification.setSpatialResolutions(Collections.singleton(resolution)); /** * Fills AcquisitionInfo */ final DefaultAcquisitionInformation acquisitionInfo = getAcquisitionInfo(metadata); //MetaData > AcquisitionInfo > Operations final DefaultOperation operation = new DefaultOperation(); operation.setIdentifier(new DefaultIdentifier(String.valueOf(missionIndex))); operation.setDescription(new SimpleInternationalString(missionName)); acquisitionInfo.getOperations().add(operation); //MetaData > AcquisitionInfo > Instruments final DefaultInstrument instrument = new DefaultInstrument(); instrument.setIdentifier(new DefaultIdentifier(instrumentName + instrumentIndex)); instrument.setDescription(new SimpleInternationalString(instrumentName)); acquisitionInfo.getInstruments().add(instrument); //MetaData > AcquisitionInfo > Platforms final DefaultCitation platformCitation = new DefaultCitation(); platformCitation.setTitle(new SimpleInternationalString(missionName)); final DefaultPlatform platform = new DefaultPlatform(); platform.setIdentifier(new DefaultIdentifier(missionName + missionIndex)); platform.setCitation(platformCitation); platform.setDescription(new SimpleInternationalString(missionName + missionIndex)); acquisitionInfo.getPlatforms().add(platform); /** * Fills ContentInfo */ //MetaData > ContentInfo (ImageDescription) > IlluminationAzimuthAngle AND IlluminationElevationAngle final DefaultImageDescription contentInfo = (DefaultImageDescription) getContentInfo(metadata); contentInfo.setIlluminationAzimuthAngle(sunAzimuth); contentInfo.setIlluminationElevationAngle(sunElevation); } } } return metadata; } /** * Extract imaging date from metadata tags {@code <IMAGING_DATE> and <IMAGING_TIME>}. * * @param doc dimap root Element * @return a date or null if tags not found */ public static Date getImagingDate(Element doc) { final Element sceneSource = firstElement(doc, TAG_SCENE_SOURCE); if (sceneSource != null) { String imagingDate = textValueSafe(sceneSource, TAG_SCENE_IMAGING_DATE, String.class); String imagingTime = textValueSafe(sceneSource, TAG_SCENE_IMAGING_TIME, String.class); if (imagingDate != null && imagingTime != null) { final ISODateParser dateParser = new ISODateParser(); return dateParser.parseToDate(imagingDate + "T" + imagingTime+ "Z"); //UTC } } return null; } public static Date getProductionDate(Element doc) { final Element production = firstElement(doc, TAG_PRODUCTION); return textValueSafe(production, TAG_DATASET_PRODUCTION_DATE, Date.class); } private static URI generateFileName(String name, String extention) { try { return new URI(name.replaceAll(":", "_").replaceAll(" ", "_").replaceAll("/", "_").concat(extention)); } catch (URISyntaxException e) { return null; } } private static DefaultProcessing getProcessingInfo(final DefaultMetadata metadata) { final DefaultProcessStep step = getProcessStep(metadata); DefaultProcessing processing = (DefaultProcessing) step.getProcessingInformation(); if (processing == null) { processing = new DefaultProcessing(); step.setProcessingInformation(processing); } return processing; } private static DefaultProcessStep getProcessStep(final DefaultMetadata metadata) { final DefaultLineage lineage = getLineage(metadata); final Collection<ProcessStep> steps = lineage.getProcessSteps(); if (steps.isEmpty()) { final DefaultProcessStep step = new DefaultProcessStep(); steps.add(step); return step; } else { final List<ProcessStep> copies = new ArrayList<ProcessStep>(steps); final ProcessStep step = copies.get(0); if (step instanceof DefaultProcessStep) { return (DefaultProcessStep) step; } else { final DefaultProcessStep copy = DefaultProcessStep.castOrCopy(step); copies.set(0, copy); //copy and replace collection lineage.setProcessSteps(copies); return copy; } } } private static DefaultLineage getLineage(final DefaultMetadata metadata) { final DefaultDataQuality quality = getDataQualityInfo(metadata); Lineage lineage = quality.getLineage(); if (lineage == null) { lineage = new DefaultLineage(); quality.setLineage(lineage); } if (lineage instanceof DefaultLineage) { return (DefaultLineage) lineage; } else { final DefaultLineage copy = DefaultLineage.castOrCopy(lineage); quality.setLineage(lineage); return copy; } } private static DefaultDataQuality getDataQualityInfo(final DefaultMetadata metadata) { final Collection<DataQuality> qualities = metadata.getDataQualityInfo(); if (qualities.isEmpty()) { final DefaultDataQuality quality = new DefaultDataQuality(); metadata.getDataQualityInfo().add(quality); return quality; } else { final List<DataQuality> copies = new ArrayList<DataQuality>(qualities); final DataQuality quality = copies.get(0); if (quality instanceof DefaultDataQuality) { return (DefaultDataQuality) quality; } else { final DefaultDataQuality copy = DefaultDataQuality.castOrCopy(quality); copies.set(0, copy); //copy and replace collection metadata.setDataQualityInfo(copies); return copy; } } } private static DefaultExtent getExtent(final DefaultMetadata metadata) { final DefaultDataIdentification identification = (DefaultDataIdentification) getIdentificationInfo(metadata); final Collection<Extent> extents = identification.getExtents(); if (extents.isEmpty()) { final DefaultExtent extent = new DefaultExtent(); extents.add(extent); return extent; } else { final List<Extent> copies = new ArrayList<Extent>(extents); final Extent extent = copies.get(0); if (extent instanceof DefaultExtent) { return (DefaultExtent) extent; } else { final DefaultExtent copy = DefaultExtent.castOrCopy(extent); copies.set(0, copy); //copy and replace collection identification.setExtents(copies); return copy; } } } private static AbstractIdentification getIdentificationInfo(final DefaultMetadata metadata) { final Collection<Identification> ids = metadata.getIdentificationInfo(); if (ids.isEmpty()) { final DefaultDataIdentification id = new DefaultDataIdentification(); ids.add(id); return id; } else { final List<Identification> copies = new ArrayList<Identification>(ids); final Identification id = copies.get(0); if (id instanceof DefaultDataIdentification) { return (DefaultDataIdentification) id; } else { final AbstractIdentification copy = DefaultDataIdentification.castOrCopy(id); copies.set(0, copy); //copy and replace collection metadata.setIdentificationInfo(copies); return copy; } } } private static DefaultBand getBandDimension(final DefaultMetadata metadata, final int bandIndex) { final DefaultImageDescription imageDescr = (DefaultImageDescription) getContentInfo(metadata); final Collection<RangeDimension> dimensions = imageDescr.getDimensions(); //Search the dimension with band identifier equals to the given identifier for (final RangeDimension dimension : dimensions) { if (dimension instanceof DefaultBand) { final String bandIdentifier = dimension.getSequenceIdentifier().toString(); if (bandIndex == Integer.parseInt(bandIdentifier)) { return (DefaultBand) dimension; } } } //If the dimension doesn't exists, creates and returns a new dimension final DefaultBand dimension = new DefaultBand(); dimensions.add(dimension); return dimension; } private static AbstractContentInformation getContentInfo(final DefaultMetadata metadata) { final Collection<ContentInformation> ids = metadata.getContentInfo(); if (ids.isEmpty()) { final DefaultImageDescription id = new DefaultImageDescription(); ids.add(id); return id; } else { final List<ContentInformation> copies = new ArrayList<ContentInformation>(ids); final ContentInformation id = copies.get(0); if (id instanceof DefaultImageDescription) { return (DefaultImageDescription) id; } else { final AbstractContentInformation copy = DefaultImageDescription.castOrCopy(id); copies.set(0, copy); //copy and replace collection metadata.setContentInfo(copies); return copy; } } } private static DefaultAcquisitionInformation getAcquisitionInfo(final DefaultMetadata metadata) { final Collection<AcquisitionInformation> acq = metadata.getAcquisitionInformation(); if (acq.isEmpty()) { final DefaultAcquisitionInformation id = new DefaultAcquisitionInformation(); acq.add(id); return id; } else { final List<AcquisitionInformation> copies = new ArrayList<AcquisitionInformation>(acq); final AcquisitionInformation id = copies.get(0); if (id instanceof DefaultAcquisitionInformation) { return (DefaultAcquisitionInformation) id; } else { final DefaultAcquisitionInformation copy = DefaultAcquisitionInformation.castOrCopy(id); copies.set(0, copy); //copy and replace collection metadata.setAcquisitionInformation(copies); return copy; } } } private static AbstractSpatialRepresentation getSpatialRepresentationInfo(final DefaultMetadata metadata) { final Collection<SpatialRepresentation> spa = metadata.getSpatialRepresentationInfo(); if (spa.isEmpty()) { final DefaultGridSpatialRepresentation sp = new DefaultGridSpatialRepresentation(); spa.add(sp); return sp; } else { final List<SpatialRepresentation> copies = new ArrayList<SpatialRepresentation>(spa); final SpatialRepresentation id = copies.get(0); if (id instanceof DefaultGridSpatialRepresentation) { return (DefaultGridSpatialRepresentation) id; } else { final AbstractSpatialRepresentation copy = DefaultGridSpatialRepresentation.castOrCopy(id); copies.set(0, copy); //copy and replace collection metadata.setSpatialRepresentationInfo(copies); return copy; } } } }