/**
* Copyright (c) Codice Foundation
* <p>
* This 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, either version 3 of the
* License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
**/
package org.codice.ddf.spatial.ogc.csw.catalog.converter;
import java.io.Serializable;
import java.net.URI;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.codice.ddf.spatial.ogc.csw.catalog.common.CswConstants;
import org.codice.ddf.spatial.ogc.csw.catalog.common.GmdConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thoughtworks.xstream.io.path.Path;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import ddf.catalog.data.Attribute;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.data.types.Contact;
import ddf.catalog.data.types.Core;
import ddf.catalog.data.types.DateTime;
import ddf.catalog.data.types.Location;
import ddf.catalog.data.types.Media;
import ddf.catalog.data.types.Topic;
import ddf.catalog.data.types.constants.core.DataType;
public class GmdConverter extends AbstractGmdConverter {
private static final Logger LOGGER = LoggerFactory.getLogger(GmdConverter.class);
@Override
protected List<String> getXstreamAliases() {
return Arrays.asList(GmdConstants.GMD_LOCAL_NAME, GmdConstants.GMD_METACARD_TYPE_NAME);
}
@Override
protected XstreamPathValueTracker buildPaths(MetacardImpl metacard) {
XstreamPathValueTracker pathValueTracker = new XstreamPathValueTracker();
pathValueTracker.add(new Path("/MD_Metadata/@xmlns"), GmdConstants.GMD_NAMESPACE);
pathValueTracker.add(new Path("/MD_Metadata/@xmlns:" + GmdConstants.GCO_PREFIX),
GmdConstants.GCO_NAMESPACE);
pathValueTracker.add(new Path("/MD_Metadata/@xmlns:" + CswConstants.GML_NAMESPACE_PREFIX),
CswConstants.GML_SCHEMA);
pathValueTracker.add(new Path(GmdConstants.FILE_IDENTIFIER_PATH), metacard.getId());
Attribute language = metacard.getAttribute(Core.LANGUAGE);
if (language != null) {
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.METADATA_LANGUAGE_PATH,
Core.LANGUAGE);
} else {
pathValueTracker.add(new Path(GmdConstants.METADATA_LANGUAGE_PATH),
Locale.ENGLISH.getISO3Language());
}
pathValueTracker.add(new Path(GmdConstants.CODE_LIST_VALUE_PATH),
StringUtils.defaultIfEmpty(metacard.getContentTypeName(),
DataType.DATASET.toString()));
pathValueTracker.add(new Path(GmdConstants.CODE_LIST_PATH), GmdConstants.METACARD_URI);
addStringAttributeToXml(metacard,
pathValueTracker,
GmdConstants.CODE_LIST_VALUE_PATH,
Core.DATATYPE,
Metacard.CONTENT_TYPE);
pathValueTracker.add(new Path(GmdConstants.CODE_LIST_PATH), GmdConstants.METACARD_URI);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.CONTACT_ORGANISATION_PATH,
Contact.POINT_OF_CONTACT_NAME);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.CONTACT_EMAIL_PATH,
Contact.POINT_OF_CONTACT_EMAIL);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.CONTACT_PHONE_PATH,
Contact.POINT_OF_CONTACT_PHONE);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.CONTACT_ADDRESS_DELIVERY_POINT_PATH,
Contact.POINT_OF_CONTACT_ADDRESS);
addDateAttributeToXml(metacard,
pathValueTracker,
GmdConstants.DATE_TIME_STAMP_PATH,
Core.METACARD_MODIFIED);
addCRSInformation(metacard, pathValueTracker);
addIdentificationInfo(metacard, pathValueTracker);
addDistributionInfo(metacard, pathValueTracker);
return pathValueTracker;
}
@Override
protected String getRootNodeName() {
return GmdConstants.GMD_LOCAL_NAME;
}
protected void addDistributionInfo(MetacardImpl metacard,
XstreamPathValueTracker pathValueTracker) {
addStringAttributeToXml(metacard,
pathValueTracker,
GmdConstants.FORMAT_PATH,
Media.FORMAT,
null);
addStringAttributeToXml(metacard,
pathValueTracker,
GmdConstants.FORMAT_VERSION_PATH,
Media.FORMAT_VERSION,
null);
String resourceUrl = null;
Attribute downloadUrlAttr = metacard.getAttribute(Core.RESOURCE_DOWNLOAD_URL);
if (downloadUrlAttr != null) {
Serializable downloadUrl = downloadUrlAttr.getValue();
if (downloadUrl instanceof String) {
resourceUrl = (String) downloadUrl;
}
}
if (StringUtils.isNotEmpty(resourceUrl)) {
pathValueTracker.add(new Path(GmdConstants.LINKAGE_URI_PATH), resourceUrl);
} else {
URI resourceUri = metacard.getResourceURI();
if (resourceUri != null) {
pathValueTracker.add(new Path(GmdConstants.LINKAGE_URI_PATH),
resourceUri.toASCIIString());
}
}
}
protected void addCRSInformation(MetacardImpl metacard,
XstreamPathValueTracker pathValueTracker) {
Attribute attribute = metacard.getAttribute(Location.COORDINATE_REFERENCE_SYSTEM_CODE);
if (attribute != null && CollectionUtils.isNotEmpty(attribute.getValues())) {
attribute.getValues()
.forEach(serializable -> {
if (serializable instanceof String) {
String[] crsSplit = ((String) serializable).split(":", 2);
if (crsSplit.length == 2) {
pathValueTracker.add(new Path(GmdConstants.CRS_CODE_PATH),
crsSplit[1]);
pathValueTracker.add(new Path(GmdConstants.CRS_AUTHORITY_PATH),
crsSplit[0]);
}
}
});
}
}
protected void addIdentificationInfo(MetacardImpl metacard,
XstreamPathValueTracker pathValueTracker) {
pathValueTracker.add(new Path(GmdConstants.TITLE_PATH),
StringUtils.defaultString(metacard.getTitle()));
addDateAttributeToXml(metacard,
pathValueTracker,
GmdConstants.CREATED_DATE_PATH,
Core.CREATED);
pathValueTracker.add(new Path(GmdConstants.CREATED_DATE_TYPE_CODE_PATH),
GmdConstants.METACARD_URI);
pathValueTracker.add(new Path(GmdConstants.CREATED_DATE_TYPE_CODE_VALUE_PATH),
Core.CREATED);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.ABSTRACT_PATH,
Core.DESCRIPTION);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.POINT_OF_CONTACT_PATH,
Contact.PUBLISHER_NAME);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.POINT_OF_CONTACT_EMAIL_PATH,
Contact.PUBLISHER_EMAIL);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.POINT_OF_CONTACT_PHONE_PATH,
Contact.PUBLISHER_PHONE);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.POINT_OF_CONTACT_ADDRESS_DELIVERY_POINT_PATH,
Contact.PUBLISHER_ADDRESS);
addListAttributeToXml(metacard, pathValueTracker, GmdConstants.KEYWORD_PATH, Topic.KEYWORD);
Attribute language = metacard.getAttribute(Core.LANGUAGE);
if (language != null) {
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.LANGUAGE_PATH,
Core.LANGUAGE);
} else {
pathValueTracker.add(new Path(GmdConstants.LANGUAGE_PATH),
Locale.ENGLISH.getISO3Language());
}
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.TOPIC_CATEGORY_PATH,
Topic.CATEGORY);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.ALTITUDE_PATH,
Location.ALTITUDE);
addListAttributeToXml(metacard,
pathValueTracker,
GmdConstants.COUNTRY_CODE_PATH,
Location.COUNTRY_CODE);
addGeospatialExtent(metacard, pathValueTracker);
addTemporalExtent(metacard, pathValueTracker);
}
private void addTemporalExtent(MetacardImpl metacard,
XstreamPathValueTracker pathValueTracker) {
addDateAttributeToXml(metacard,
pathValueTracker,
GmdConstants.TEMPORAL_START_PATH,
DateTime.START);
addDateAttributeToXml(metacard,
pathValueTracker,
GmdConstants.TEMPORAL_STOP_PATH,
DateTime.END);
}
protected void addGeospatialExtent(MetacardImpl metacard,
XstreamPathValueTracker pathValueTracker) {
String wkt = metacard.getLocation();
if (StringUtils.isNotBlank(wkt)) {
WKTReader reader = new WKTReader();
Geometry geometry = null;
try {
geometry = reader.read(wkt);
} catch (ParseException e) {
LOGGER.debug("Unable to parse geometry {}", wkt, e);
}
if (geometry != null) {
Envelope bounds = geometry.getEnvelopeInternal();
String westLon = Double.toString(bounds.getMinX());
String eastLon = Double.toString(bounds.getMaxX());
String southLat = Double.toString(bounds.getMinY());
String northLat = Double.toString(bounds.getMaxY());
pathValueTracker.add(new Path(GmdConstants.BBOX_WEST_LON_PATH), westLon);
pathValueTracker.add(new Path(GmdConstants.BBOX_EAST_LON_PATH), eastLon);
pathValueTracker.add(new Path(GmdConstants.BBOX_SOUTH_LAT_PATH), southLat);
pathValueTracker.add(new Path(GmdConstants.BBOX_NORTH_LAT_PATH), northLat);
}
}
}
private void addStringAttributeToXml(Metacard metacard,
XstreamPathValueTracker pathValueTracker, String path, String metacardAttributeName,
String fallbackMetacardAttribute) {
Attribute attribute = metacard.getAttribute(metacardAttributeName);
if (attribute != null) {
addStringAttributeToPath(attribute, pathValueTracker, path);
} else if (StringUtils.isNotEmpty(fallbackMetacardAttribute)) {
Attribute fallbackAttribute = metacard.getAttribute(fallbackMetacardAttribute);
if (fallbackAttribute != null) {
addStringAttributeToPath(fallbackAttribute, pathValueTracker, path);
}
}
}
private void addStringAttributeToPath(Attribute attribute,
XstreamPathValueTracker pathValueTracker, String path) {
Serializable serializable = attribute.getValue();
if (serializable instanceof String) {
String value = (String) serializable;
pathValueTracker.add(new Path(path), value);
}
}
private void addDateAttributeToXml(Metacard metacard, XstreamPathValueTracker pathValueTracker,
String path, String metcardAttributeName) {
Attribute attribute = metacard.getAttribute(metcardAttributeName);
if (attribute != null) {
Serializable serializable = attribute.getValue();
if (serializable instanceof Date) {
GregorianCalendar modifiedCal = new GregorianCalendar();
modifiedCal.setTime((Date) serializable);
modifiedCal.setTimeZone(UTC_TIME_ZONE);
pathValueTracker.add(new Path(path),
XSD_FACTORY.newXMLGregorianCalendar(modifiedCal)
.toXMLFormat());
}
}
}
private void addListAttributeToXml(Metacard metacard, XstreamPathValueTracker pathValueTracker,
String path, String metacardAttribute) {
Attribute descriptions = metacard.getAttribute(metacardAttribute);
if (descriptions != null && CollectionUtils.isNotEmpty(descriptions.getValues())) {
pathValueTracker.add(new Path(path),
descriptions.getValues()
.stream()
.map(Serializable::toString)
.collect(Collectors.toList()));
}
}
}