
thredds.catalog.parser.jdom.InvCatalogFactory10 Maven / Gradle / Ivy
/*
* Copyright 1998-2014 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package thredds.catalog.parser.jdom;
import thredds.featurecollection.FeatureCollectionConfig;
import thredds.util.PathAliasReplacement;
import thredds.catalog.*;
import thredds.crawlabledataset.*;
import thredds.crawlabledataset.sorter.LexigraphicByNameSorter;
import thredds.crawlabledataset.filter.*;
import thredds.cataloggen.ProxyDatasetHandler;
import thredds.cataloggen.DatasetEnhancer;
import thredds.cataloggen.CatalogRefExpander;
import thredds.cataloggen.datasetenhancer.RegExpAndDurationTimeCoverageEnhancer;
import thredds.cataloggen.inserter.SimpleLatestProxyDsHandler;
import thredds.cataloggen.inserter.LatestCompleteProxyDsHandler;
import org.jdom2.*;
import org.jdom2.input.*;
import org.jdom2.output.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.FeatureType;
import ucar.nc2.units.TimeDuration;
import ucar.nc2.units.DateRange;
import ucar.nc2.units.DateType;
/**
* Inventory Catalog parser, version 1.0.
* Reads InvCatalog.xml files, constructs object representation.
*
* @author John Caron
*/
public class InvCatalogFactory10 implements InvCatalogConvertIF, MetadataConverterIF {
static private org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InvCatalogFactory10.class);
static public final Namespace defNS = Namespace.getNamespace(XMLEntityResolver.CATALOG_NAMESPACE_10);
static public final Namespace xlinkNS = Namespace.getNamespace("xlink", XMLEntityResolver.XLINK_NAMESPACE);
static public final Namespace ncmlNS = Namespace.getNamespace("ncml", XMLEntityResolver.NJ22_NAMESPACE);
static private boolean useBytesForDataSize = false;
static public void useBytesForDataSize(boolean b) {
useBytesForDataSize = b;
}
private InvCatalogFactory factory = null;
private String version = "1.0.1";
private boolean debugMetadataRead = false;
private List dataRootLocAliasExpanders = Collections.emptyList();
public void setDataRootLocationAliasExpanders(List dataRootLocAliasExpanders) {
if (dataRootLocAliasExpanders == null)
this.dataRootLocAliasExpanders = Collections.emptyList();
else
this.dataRootLocAliasExpanders = new ArrayList<>(dataRootLocAliasExpanders);
}
public List getDataRootLocationAliasExpanders() {
return Collections.unmodifiableList(this.dataRootLocAliasExpanders);
}
private String expandAliasForPath(String location) {
for (PathAliasReplacement par : this.dataRootLocAliasExpanders) {
if (par.containsPathAlias(location)) {
return par.replacePathAlias(location);
}
}
return location;
}
private String expandAliasForCollectionSpec(String location) {
for (PathAliasReplacement par : this.dataRootLocAliasExpanders) {
String result = par.replaceIfMatch(location);
if (result != null) return result;
}
return location;
}
public InvCatalogImpl parseXML(InvCatalogFactory fac, org.jdom2.Document jdomDoc, URI uri) {
this.factory = fac;
return readCatalog(jdomDoc.getRootElement(), uri);
}
private Map metadataHash = new HashMap<>(10);
public void registerMetadataConverter(MetadataType type, MetadataConverterIF converter) {
metadataHash.put(type, converter);
}
public void setVersion(String version) {
this.version = version;
}
/////////////////////////////////////////////////////////////////////////////
protected InvAccessImpl readAccess(InvDatasetImpl dataset, Element accessElem) {
String urlPath = accessElem.getAttributeValue("urlPath");
String serviceName = accessElem.getAttributeValue("serviceName");
String dataFormat = accessElem.getAttributeValue("dataFormat");
return new InvAccessImpl(dataset, urlPath, serviceName, null, dataFormat, readDataSize(accessElem));
}
protected InvCatalogImpl readCatalog(Element catalogElem, URI docBaseURI) {
String name = catalogElem.getAttributeValue("name");
String catSpecifiedBaseURL = catalogElem.getAttributeValue("base");
String expires = catalogElem.getAttributeValue("expires");
String version = catalogElem.getAttributeValue("version");
URI baseURI = docBaseURI;
if (catSpecifiedBaseURL != null) {
try {
baseURI = new URI(catSpecifiedBaseURL);
} catch (URISyntaxException e) {
logger.debug("readCatalog(): bad catalog specified base URI <" + catSpecifiedBaseURL + ">: " + e.getMessage(), e);
baseURI = docBaseURI;
}
}
InvCatalogImpl catalog = new InvCatalogImpl(name, version, makeDateType(expires, null, null), baseURI);
// read top-level services
java.util.List sList = catalogElem.getChildren("service", defNS);
for (Element e : sList) {
InvService s = readService(e, baseURI);
catalog.addService(s);
}
// read top-level properties
java.util.List pList = catalogElem.getChildren("property", defNS);
for (Element e : pList) {
InvProperty s = readProperty(e);
catalog.addProperty(s);
}
// read top-level dataroots
java.util.List rootList = catalogElem.getChildren("datasetRoot", defNS);
for (Element e : rootList) {
DataRootConfig root = readDatasetRoot(e);
catalog.addDatasetRoot(root);
}
// look for top-level dataset and catalogRefs elements (keep them in order)
java.util.List allChildren = catalogElem.getChildren();
for (Element e : allChildren) {
if (e.getName().equals("dataset")) {
catalog.addDataset(readDataset(catalog, null, e, baseURI));
} else if (e.getName().equals("featureCollection")) {
catalog.addDataset(readFeatureCollection(catalog, null, e, baseURI));
} else if (e.getName().equals("datasetScan")) {
catalog.addDataset(readDatasetScan(catalog, null, e, baseURI));
} else if (e.getName().equals("catalogRef")) {
catalog.addDataset(readCatalogRef(catalog, null, e, baseURI));
}
}
return catalog;
}
protected InvCatalogRef readCatalogRef(InvCatalogImpl cat, InvDatasetImpl parent, Element catRefElem, URI baseURI) {
String title = catRefElem.getAttributeValue("title", xlinkNS);
if (title == null) title = catRefElem.getAttributeValue("name");
String href = catRefElem.getAttributeValue("href", xlinkNS);
String useRemCatSerStr = catRefElem.getAttributeValue("useRemoteCatalogService");
Boolean useRemoteCatalogService = null;
if (useRemCatSerStr != null) useRemoteCatalogService = Boolean.parseBoolean(useRemCatSerStr);
InvCatalogRef catRef = new InvCatalogRef(parent, title, href, useRemoteCatalogService);
readDatasetInfo(cat, catRef, catRefElem, baseURI);
return catRef;
}
protected ThreddsMetadata.Contributor readContributor(Element elem) {
if (elem == null) return null;
return new ThreddsMetadata.Contributor(elem.getText(), elem.getAttributeValue("role"));
}
protected ThreddsMetadata.Vocab readControlledVocabulary(Element elem) {
if (elem == null) return null;
return new ThreddsMetadata.Vocab(elem.getText(), elem.getAttributeValue("vocabulary"));
}
// read a dataset element
protected InvDatasetImpl readDataset(InvCatalogImpl catalog, InvDatasetImpl parent, Element dsElem, URI base) {
// deal with aliases
String name = dsElem.getAttributeValue("name");
String alias = dsElem.getAttributeValue("alias");
if (alias != null) {
InvDatasetImpl ds = (InvDatasetImpl) catalog.findDatasetByID(alias);
if (ds == null) {
factory.appendErr(" ** Parse error: dataset named " + name + " has illegal alias = " + alias + "\n");
return null;
}
return new InvDatasetImplProxy(name, ds);
}
InvDatasetImpl dataset = new InvDatasetImpl(parent, name);
readDatasetInfo(catalog, dataset, dsElem, base);
if (InvCatalogFactory.debugXML) System.out.println(" Dataset added: " + dataset.dump());
return dataset;
}
protected void readDatasetInfo(InvCatalogImpl catalog, InvDatasetImpl dataset, Element dsElem, URI base) {
// read attributes
String authority = dsElem.getAttributeValue("authority");
String collectionTypeName = dsElem.getAttributeValue("collectionType");
String dataTypeName = dsElem.getAttributeValue("dataType");
String harvest = dsElem.getAttributeValue("harvest");
String id = dsElem.getAttributeValue("ID");
String serviceName = dsElem.getAttributeValue("serviceName");
String urlPath = dsElem.getAttributeValue("urlPath");
String restrictAccess = dsElem.getAttributeValue("restrictAccess");
FeatureType dataType = null;
if (dataTypeName != null) {
dataType = FeatureType.getType(dataTypeName.toUpperCase());
if (dataType == null) {
factory.appendWarning(" ** warning: non-standard data type = " + dataTypeName + "\n");
}
}
if (dataType != null)
dataset.setDataType(dataType);
if (serviceName != null)
dataset.setServiceName(serviceName);
if (urlPath != null)
dataset.setUrlPath(urlPath);
if (authority != null) dataset.setAuthority(authority);
if (id != null) dataset.setID(id);
if (harvest != null) dataset.setHarvest(harvest.equalsIgnoreCase("true"));
if (restrictAccess != null) dataset.setResourceControl(restrictAccess);
if (collectionTypeName != null) {
CollectionType collectionType = CollectionType.findType(collectionTypeName);
if (collectionType == null) {
collectionType = CollectionType.getType(collectionTypeName);
factory.appendWarning(" ** warning: non-standard collection type = " + collectionTypeName + "\n");
}
dataset.setCollectionType(collectionType);
}
catalog.addDatasetByID(dataset); // need to do immed for alias processing
// look for services
java.util.List serviceList = dsElem.getChildren("service", defNS);
for (Element curElem : serviceList) {
InvService s = readService(curElem, base);
dataset.addService(s);
}
// look for direct thredds metadata (not inherited)
ThreddsMetadata tmg = dataset.getLocalMetadata();
readThreddsMetadata(catalog, dataset, dsElem, tmg);
// look for access elements
java.util.List aList = dsElem.getChildren("access", defNS);
for (Element e : aList) {
InvAccessImpl a = readAccess(dataset, e);
dataset.addAccess(a);
}
// look for ncml
Element ncmlElem = dsElem.getChild("netcdf", ncmlNS);
if (ncmlElem != null) {
ncmlElem.detach();
dataset.setNcmlElement(ncmlElem);
// System.out.println(" found ncml= "+ncmlElem);
}
// look for nested dataset and catalogRefs elements (keep them in order)
java.util.List allChildren = dsElem.getChildren();
for (Element e : allChildren) {
if (e.getName().equals("dataset")) {
InvDatasetImpl ds = readDataset(catalog, dataset, e, base);
if (ds != null)
dataset.addDataset(ds);
} else if (e.getName().equals("catalogRef")) {
InvDatasetImpl ds = readCatalogRef(catalog, dataset, e, base);
dataset.addDataset(ds);
} else if (e.getName().equals("datasetScan")) {
dataset.addDataset(readDatasetScan(catalog, dataset, e, base));
} else if (e.getName().equals("featureCollection")) {
InvDatasetImpl ds = readFeatureCollection(catalog, dataset, e, base);
if (ds != null)
dataset.addDataset(ds);
}
}
}
protected InvDatasetImpl readFeatureCollection(InvCatalogImpl catalog, InvDatasetImpl parent, Element dsElem, URI base) {
FeatureCollectionConfig config = FeatureCollectionReader.readFeatureCollection(dsElem);
config.spec = expandAliasForCollectionSpec(config.spec);
try {
InvDatasetFeatureCollection ds = InvDatasetFeatureCollection.factory(parent, config.name, config.path, config.type, config);
if (ds == null) {
logger.error("featureCollection " + config.name + " has fatal error ");
return null;
}
// regular dataset elements
readDatasetInfo(catalog, ds, dsElem, base);
return ds;
} catch (Exception e) {
logger.error("featureCollection " + config.name + " has fatal error, skipping ", e);
return null;
}
}
// read a dataset scan element
protected InvDatasetScan readDatasetScan(InvCatalogImpl catalog, InvDatasetImpl parent, Element dsElem, URI base) {
InvDatasetScan datasetScan;
if (dsElem.getAttributeValue("dirLocation") == null) {
if (dsElem.getAttributeValue("location") == null) {
logger.error("readDatasetScan(): datasetScan has neither a \"location\" nor a \"dirLocation\" attribute.");
datasetScan = null;
} else {
return readDatasetScanNew(catalog, parent, dsElem, base);
}
} else {
String name = dsElem.getAttributeValue("name");
factory.appendWarning("**Warning: Dataset " + name + " using old form of DatasetScan (dirLocation instead of location)\n");
String path = dsElem.getAttributeValue("path");
String scanDir = expandAliasForPath(dsElem.getAttributeValue("dirLocation"));
String filter = dsElem.getAttributeValue("filter");
String addDatasetSizeString = dsElem.getAttributeValue("addDatasetSize");
String addLatest = dsElem.getAttributeValue("addLatest");
String sortOrderIncreasingString = dsElem.getAttributeValue("sortOrderIncreasing");
boolean sortOrderIncreasing = false;
if (sortOrderIncreasingString != null)
if (sortOrderIncreasingString.equalsIgnoreCase("true"))
sortOrderIncreasing = true;
boolean addDatasetSize = true;
if (addDatasetSizeString != null)
if (addDatasetSizeString.equalsIgnoreCase("false"))
addDatasetSize = false;
if (path != null) {
if (path.charAt(0) == '/') path = path.substring(1);
int last = path.length() - 1;
if (path.charAt(last) == '/') path = path.substring(0, last);
}
if (scanDir != null) {
int last = scanDir.length() - 1;
if (scanDir.charAt(last) != '/') scanDir = scanDir + '/';
}
Element atcElem = dsElem.getChild("addTimeCoverage", defNS);
String dsNameMatchPattern = null;
String startTimeSubstitutionPattern = null;
String duration = null;
if (atcElem != null) {
dsNameMatchPattern = atcElem.getAttributeValue("datasetNameMatchPattern");
startTimeSubstitutionPattern = atcElem.getAttributeValue("startTimeSubstitutionPattern");
duration = atcElem.getAttributeValue("duration");
}
try {
datasetScan = new InvDatasetScan(catalog, parent, name, path, scanDir, filter, addDatasetSize, addLatest, sortOrderIncreasing,
dsNameMatchPattern, startTimeSubstitutionPattern, duration);
readDatasetInfo(catalog, datasetScan, dsElem, base);
if (InvCatalogFactory.debugXML) System.out.println(" Dataset added: " + datasetScan.dump());
} catch (Exception e) {
logger.error("Reading DatasetScan", e);
datasetScan = null;
}
}
return datasetScan;
}
protected InvDatasetScan readDatasetScanNew(InvCatalogImpl catalog, InvDatasetImpl parent, Element dsElem, URI base) {
String name = dsElem.getAttributeValue("name");
String path = dsElem.getAttributeValue("path");
String scanDir = expandAliasForPath(dsElem.getAttributeValue("location"));
// Read datasetConfig element
String configClassName = null;
Object configObj = null;
Element dsConfigElem = dsElem.getChild("crawlableDatasetImpl", defNS);
if (dsConfigElem != null) {
configClassName = dsConfigElem.getAttributeValue("className");
List children = dsConfigElem.getChildren();
if (children.size() == 1) {
configObj = children.get(0);
} else if (children.size() != 0) {
logger.warn("readDatasetScanNew(): content of datasetConfig element not a single element, using first element.");
configObj = children.get(0);
} else {
logger.debug("readDatasetScanNew(): datasetConfig element has no children.");
configObj = null;
}
}
// Read filter element
Element filterElem = dsElem.getChild("filter", defNS);
CrawlableDatasetFilter filter = null;
if (filterElem != null)
filter = readDatasetScanFilter(filterElem);
// Read identifier element
Element identifierElem = dsElem.getChild("addID", defNS);
CrawlableDatasetLabeler identifier = null;
if (identifierElem != null) {
identifier = readDatasetScanIdentifier(identifierElem);
}
// Read namer element
Element namerElem = dsElem.getChild("namer", defNS);
CrawlableDatasetLabeler namer = null;
if (namerElem != null) {
namer = readDatasetScanNamer(namerElem);
}
// Read sort element
Element sorterElem = dsElem.getChild("sort", defNS);
// By default, sort in decreasing lexigraphic order.
CrawlableDatasetSorter sorter = new LexigraphicByNameSorter(false);
if (sorterElem != null) {
sorter = readDatasetScanSorter(sorterElem);
}
// Read allProxies element (and addLatest element)
Element addLatestElem = dsElem.getChild("addLatest", defNS);
Element addProxiesElem = dsElem.getChild("addProxies", defNS);
Map allProxyDsHandlers;
if (addLatestElem != null || addProxiesElem != null)
allProxyDsHandlers = readDatasetScanAddProxies(addProxiesElem, addLatestElem, catalog);
else
allProxyDsHandlers = new HashMap<>();
// Read addDatasetSize element.
Element addDsSizeElem = dsElem.getChild("addDatasetSize", defNS);
//boolean addDatasetSize = false; old way
//if ( addDsSizeElem != null )
// addDatasetSize = true;
boolean addDatasetSize = true;
if (addDsSizeElem != null) {
if (addDsSizeElem.getTextNormalize().equalsIgnoreCase("false"))
addDatasetSize = false;
}
// Read addTimeCoverage element.
List childEnhancerList = new ArrayList<>();
Element addTimeCovElem = dsElem.getChild("addTimeCoverage", defNS);
if (addTimeCovElem != null) {
DatasetEnhancer addTimeCovEnhancer = readDatasetScanAddTimeCoverage(addTimeCovElem);
if (addTimeCovEnhancer != null)
childEnhancerList.add(addTimeCovEnhancer);
}
// Read datasetEnhancerImpl elements (user defined implementations of DatasetEnhancer)
List dsEnhancerElemList = dsElem.getChildren("datasetEnhancerImpl", defNS);
for (Element elem : dsEnhancerElemList) {
DatasetEnhancer o = readDatasetScanUserDefined(elem, DatasetEnhancer.class);
if (o != null)
childEnhancerList.add(o);
}
// Read catalogRefExpander element
// Element catRefExpanderElem = dsElem.getChild( "catalogRefExpander", defNS );
CatalogRefExpander catalogRefExpander = null;
// if ( catRefExpanderElem != null )
// {
// catalogRefExpander = readDatasetScanCatRefExpander( catRefExpanderElem );
// }
InvDatasetScan datasetScan;
try {
datasetScan = new InvDatasetScan(parent, name, path, scanDir,
configClassName, configObj,
filter, identifier, namer,
addDatasetSize, sorter, allProxyDsHandlers,
childEnhancerList,
catalogRefExpander);
readDatasetInfo(catalog, datasetScan, dsElem, base);
if (InvCatalogFactory.debugXML) System.out.println(" Dataset added: " + datasetScan.dump());
} catch (Exception e) {
logger.error("readDatasetScanNew(): failed to create DatasetScan", e);
datasetScan = null;
}
return datasetScan;
}
CrawlableDatasetFilter readDatasetScanFilter(Element filterElem) {
CrawlableDatasetFilter filter = null; //lastModifiedLimit
// Handle LastModifiedLimitFilter CrDsFilters.
Attribute lastModLimitAtt = filterElem.getAttribute("lastModifiedLimit");
if (lastModLimitAtt != null) {
long lastModLimit;
try {
lastModLimit = lastModLimitAtt.getLongValue();
} catch (DataConversionException e) {
String tmpMsg = "readDatasetScanFilter(): bad lastModifedLimit value <" + lastModLimitAtt.getValue() + ">, couldn't parse into long: " + e.getMessage();
factory.appendErr(tmpMsg);
logger.warn(tmpMsg);
return null;
}
return new LastModifiedLimitFilter(lastModLimit);
}
// Handle LogicalFilterComposer CrDsFilters.
String compType = filterElem.getAttributeValue("logicalComp");
if (compType != null) {
List filters = filterElem.getChildren("filter", defNS);
if (compType.equalsIgnoreCase("AND")) {
if (filters.size() != 2) {
String tmpMsg = "readDatasetScanFilter(): wrong number of filters <" + filters.size() + "> for AND (2 expected).";
factory.appendErr(tmpMsg);
logger.warn(tmpMsg);
return null;
}
filter = LogicalFilterComposer.getAndFilter(
readDatasetScanFilter((Element) filters.get(0)),
readDatasetScanFilter((Element) filters.get(1)));
} else if (compType.equalsIgnoreCase("OR")) {
if (filters.size() != 2) {
String tmpMsg = "readDatasetScanFilter(): wrong number of filters <" + filters.size() + "> for OR (2 expected).";
factory.appendErr(tmpMsg);
logger.warn(tmpMsg);
return null;
}
filter = LogicalFilterComposer.getOrFilter(
readDatasetScanFilter((Element) filters.get(0)),
readDatasetScanFilter((Element) filters.get(1)));
} else if (compType.equalsIgnoreCase("NOT")) {
if (filters.size() != 1) {
String tmpMsg = "readDatasetScanFilter(): wrong number of filters <" + filters.size() + "> for NOT (1 expected).";
factory.appendErr(tmpMsg);
logger.warn(tmpMsg);
return null;
}
filter = LogicalFilterComposer.getNotFilter(
readDatasetScanFilter((Element) filters.get(0)));
}
return filter;
}
// Handle user defined CrDsFilters.
Element userDefElem = filterElem.getChild("crawlableDatasetFilterImpl", defNS);
if (userDefElem != null) {
filter = (CrawlableDatasetFilter) readDatasetScanUserDefined(userDefElem, CrawlableDatasetFilter.class);
}
// Handle MultiSelectorFilter and contained Selectors.
else {
List selectorList = new ArrayList<>();
for (Element curElem : filterElem.getChildren()) {
String regExpAttVal = curElem.getAttributeValue("regExp");
String wildcardAttVal = curElem.getAttributeValue("wildcard");
String lastModLimitAttVal = curElem.getAttributeValue("lastModLimitInMillis");
if (regExpAttVal == null && wildcardAttVal == null && lastModLimitAttVal == null) {
// If no regExp or wildcard attributes, skip this selector.
logger.warn("readDatasetScanFilter(): no regExp, wildcard, or lastModLimitInMillis attribute in filter child <" + curElem.getName() + ">.");
} else {
// Determine if applies to atomic datasets, default true.
boolean atomic = true;
String atomicAttVal = curElem.getAttributeValue("atomic");
if (atomicAttVal != null) {
// If not "true", set to false.
if (!atomicAttVal.equalsIgnoreCase("true"))
atomic = false;
}
// Determine if applies to collection datasets, default false.
boolean collection = false;
String collectionAttVal = curElem.getAttributeValue("collection");
if (collectionAttVal != null) {
// If not "false", set to true.
if (!collectionAttVal.equalsIgnoreCase("false"))
collection = true;
}
// Determine if include or exclude selectors.
boolean includer = true;
if (curElem.getName().equals("exclude")) {
includer = false;
} else if (!curElem.getName().equals("include")) {
logger.warn("readDatasetScanFilter(): unhandled filter child <" + curElem.getName() + ">.");
continue;
}
// Determine if regExp or wildcard
if (regExpAttVal != null) {
selectorList.add(new MultiSelectorFilter.Selector(new RegExpMatchOnNameFilter(regExpAttVal), includer, atomic, collection));
} else if (wildcardAttVal != null) {
selectorList.add(new MultiSelectorFilter.Selector(new WildcardMatchOnNameFilter(wildcardAttVal), includer, atomic, collection));
} else if (lastModLimitAttVal != null) {
selectorList.add(new MultiSelectorFilter.Selector(new LastModifiedLimitFilter(Long.parseLong(lastModLimitAttVal)), includer, atomic, collection));
}
}
}
filter = new MultiSelectorFilter(selectorList);
}
return filter;
}
protected CrawlableDatasetLabeler readDatasetScanIdentifier(Element identifierElem) {
CrawlableDatasetLabeler identifier;
Element userDefElem = identifierElem.getChild("crawlableDatasetLabelerImpl", defNS);
if (userDefElem != null) {
identifier = (CrawlableDatasetLabeler) readDatasetScanUserDefined(userDefElem, CrawlableDatasetLabeler.class);
} else {
// Default is to add ID in standard way. Don't have alternates yet.
return null;
}
return identifier;
}
protected CrawlableDatasetLabeler readDatasetScanNamer(Element namerElem) {
CrawlableDatasetLabeler namer;
// Element userDefElem = namerElem.getChild( "crawlableDatasetLabelerImpl", defNS );
// if ( userDefElem != null )
// {
// namer = (CrawlableDatasetLabeler) readDatasetScanUserDefined( userDefElem, CrawlableDatasetLabeler.class );
// }
// else
// {
List labelerList = new ArrayList<>();
for (Element curElem : namerElem.getChildren()) {
CrawlableDatasetLabeler curLabeler;
String regExp = curElem.getAttributeValue("regExp");
String replaceString = curElem.getAttributeValue("replaceString");
if (curElem.getName().equals("regExpOnName")) {
curLabeler = new RegExpAndReplaceOnNameLabeler(regExp, replaceString);
} else if (curElem.getName().equals("regExpOnPath")) {
curLabeler = new RegExpAndReplaceOnPathLabeler(regExp, replaceString);
} else {
logger.warn("readDatasetScanNamer(): unhandled namer child <" + curElem.getName() + ">.");
continue;
}
labelerList.add(curLabeler);
}
namer = new MultiLabeler(labelerList);
// }
return namer;
}
protected CrawlableDatasetSorter readDatasetScanSorter(Element sorterElem) {
CrawlableDatasetSorter sorter = null;
Element userDefElem = sorterElem.getChild("crawlableDatasetSorterImpl", defNS);
if (userDefElem != null) {
sorter = (CrawlableDatasetSorter) readDatasetScanUserDefined(userDefElem, CrawlableDatasetSorter.class);
} else {
Element lexSortElem = sorterElem.getChild("lexigraphicByName", defNS);
if (lexSortElem != null) {
boolean increasing;
String increasingString = lexSortElem.getAttributeValue("increasing");
increasing = increasingString.equalsIgnoreCase("true");
sorter = new LexigraphicByNameSorter(increasing);
}
}
return sorter;
}
protected Map readDatasetScanAddProxies(Element addProxiesElem, Element addLatestElem, InvCatalogImpl catalog) {
Map allProxyDsHandlers = new HashMap<>();
// Handle old "addLatest" elements.
if (addLatestElem != null) {
// Check for simpleLatest element.
Element simpleLatestElem = addLatestElem.getChild("simpleLatest", defNS);
// Get a SimpleLatestDsHandler, use default values if element is null.
ProxyDatasetHandler pdh = readDatasetScanAddLatest(simpleLatestElem, catalog);
if (pdh != null)
allProxyDsHandlers.put(pdh.getProxyDatasetName(), pdh);
}
// Handle all "addProxies" elements.
if (addProxiesElem != null) {
for (Element curChildElem : addProxiesElem.getChildren()) {
ProxyDatasetHandler curPdh;
// Handle "simpleLatest" child elements.
if (curChildElem.getName().equals("simpleLatest")
&& curChildElem.getNamespace().equals(defNS)) {
curPdh = readDatasetScanAddLatest(curChildElem, catalog);
}
// Handle "latestComplete" child elements.
else if (curChildElem.getName().equals("latestComplete")
&& curChildElem.getNamespace().equals(defNS)) {
// Get latest name.
String latestName = curChildElem.getAttributeValue("name");
if (latestName == null) {
logger.warn("readDatasetScanAddProxies(): unnamed latestComplete, skipping.");
continue;
}
// Does latest go on top or bottom of list.
Attribute topAtt = curChildElem.getAttribute("top");
boolean latestOnTop = true;
if (topAtt != null) {
try {
latestOnTop = topAtt.getBooleanValue();
} catch (DataConversionException e) {
latestOnTop = true;
}
}
// Get the latest service name.
String serviceName = curChildElem.getAttributeValue("serviceName");
if (serviceName == null) {
logger.warn("readDatasetScanAddProxies(): no service name given in latestComplete.");
continue;
}
InvService service = catalog.findService(serviceName);
if (service == null) {
logger.warn("readDatasetScanAddProxies(): named service <" + serviceName + "> not found.");
continue;
}
// Get lastModifed limit.
String lastModLimitVal = curChildElem.getAttributeValue("lastModifiedLimit");
long lastModLimit;
if (lastModLimitVal == null)
lastModLimit = 60; // Default to one hour
else
lastModLimit = Long.parseLong(lastModLimitVal);
// Get isResolver.
String isResolverString = curChildElem.getAttributeValue("isResolver");
boolean isResolver = true;
if (isResolverString != null)
if (isResolverString.equalsIgnoreCase("false"))
isResolver = false;
// Build the SimpleLatestProxyDsHandler and add to map.
curPdh = new LatestCompleteProxyDsHandler(latestName, latestOnTop, service, isResolver, lastModLimit);
} else {
curPdh = null;
// @todo Deal with allowing user defined inserters
//Element userDefElem = addLatestElem.getChild( "proxyDatasetHandlerImpl", defNS );
}
// Add current proxy dataset handler to map if name is not already in map.
if (curPdh != null) {
if (allProxyDsHandlers.containsKey(curPdh.getProxyDatasetName())) {
logger.warn("readDatasetScanAddProxies(): proxy map already contains key <" + curPdh.getProxyDatasetName() + ">, skipping.");
continue;
}
allProxyDsHandlers.put(curPdh.getProxyDatasetName(), curPdh);
}
}
}
return allProxyDsHandlers;
}
/**
* Return a SimpleLatestProxyDsHandler, use default values if element is null.
*
* @param simpleLatestElem the simpleLatest element
* @param catalog the catalog containing the simpleLatest element.
* @return a SimpleLatestProxyDsHandler
*/
private ProxyDatasetHandler readDatasetScanAddLatest(Element simpleLatestElem, InvCatalogImpl catalog) {
// Default values is simpleLatestElem is null.
ProxyDatasetHandler latestAdder = null;
String latestName = "latest.xml";
boolean latestOnTop = true;
String latestServiceName = "latest";
boolean isResolver = true;
// If simpleLatestElem exists, read values.
if (simpleLatestElem != null) {
// Get latest name.
String tmpLatestName = simpleLatestElem.getAttributeValue("name");
if (tmpLatestName != null)
latestName = tmpLatestName;
// Does latest go on top or bottom of list.
Attribute topAtt = simpleLatestElem.getAttribute("top");
if (topAtt != null) {
try {
latestOnTop = topAtt.getBooleanValue();
} catch (DataConversionException e) {
latestOnTop = true;
}
}
// Get the latest service name.
String tmpLatestServiceName = simpleLatestElem.getAttributeValue("serviceName");
if (tmpLatestServiceName != null)
latestServiceName = tmpLatestServiceName;
// Get isResolver.
String isResolverString = simpleLatestElem.getAttributeValue("isResolver");
if (isResolverString != null)
if (isResolverString.equalsIgnoreCase("false"))
isResolver = false;
}
// Build the SimpleLatestProxyDsHandler
InvService service = catalog.findService(latestServiceName);
if (service == null)
logger.warn("readDatasetScanAddLatest(): named service <" + latestServiceName + "> not found.");
else
latestAdder = new SimpleLatestProxyDsHandler(latestName, latestOnTop, service, isResolver);
return latestAdder;
}
// protected CatalogRefExpander readDatasetScanCatRefExpander( Element catRefExpanderElem )
// {
//
// }
protected DatasetEnhancer readDatasetScanAddTimeCoverage(Element addTimeCovElem) {
DatasetEnhancer timeCovEnhancer = null;
String matchName = addTimeCovElem.getAttributeValue("datasetNameMatchPattern");
String matchPath = addTimeCovElem.getAttributeValue("datasetPathMatchPattern");
String subst = addTimeCovElem.getAttributeValue("startTimeSubstitutionPattern");
String duration = addTimeCovElem.getAttributeValue("duration");
if (matchName != null && subst != null && duration != null) {
timeCovEnhancer = RegExpAndDurationTimeCoverageEnhancer
.getInstanceToMatchOnDatasetName(matchName, subst, duration);
} else if (matchPath != null && subst != null && duration != null) {
timeCovEnhancer = RegExpAndDurationTimeCoverageEnhancer
.getInstanceToMatchOnDatasetPath(matchPath, subst, duration);
}
return timeCovEnhancer;
}
private DatasetEnhancer readDatasetScanUserDefined(Element userDefElem, Class targetClass) {
String className = userDefElem.getAttributeValue("className");
Element configElem;
List childrenElemList = userDefElem.getChildren();
if (childrenElemList.size() == 1) {
configElem = (Element) childrenElemList.get(0);
} else if (childrenElemList.size() != 0) {
logger.warn("readDatasetScanUserDefined(): config XML not a single element, using first element.");
configElem = (Element) childrenElemList.get(0);
} else {
logger.debug("readDatasetScanUserDefined(): no config XML elements.");
configElem = null;
}
try {
// Get the Class instance for desired targetClass implementation.
Class requestedClass = Class.forName(className);
// Check that the requested Class is a target Class.
if (!targetClass.isAssignableFrom(requestedClass)) {
throw new IllegalArgumentException("Requested class <" + className + "> not an implementation of " + targetClass.getName() + ".");
}
// Instantiate the desired Object using that classes constructor with a
// single Object argument.
Class[] argTypes = {Object.class};
Object[] args = {configElem};
Constructor constructor = requestedClass.getConstructor(argTypes);
return (DatasetEnhancer) constructor.newInstance(args);
} catch (ClassNotFoundException e) {
logger.warn("readDatasetScanUserDefined(): exception creating user defined object <" + className + ">", e);
return null;
} catch (NoSuchMethodException e) {
logger.warn("readDatasetScanUserDefined(): exception creating user defined object <" + className + ">", e);
return null;
} catch (InstantiationException e) {
logger.warn("readDatasetScanUserDefined(): exception creating user defined object <" + className + ">", e);
return null;
} catch (IllegalAccessException e) {
logger.warn("readDatasetScanUserDefined(): exception creating user defined object <" + className + ">", e);
return null;
} catch (InvocationTargetException e) {
logger.warn("readDatasetScanUserDefined(): exception creating user defined object <" + className + ">", e);
return null;
}
}
protected DataRootConfig readDatasetRoot(Element s) {
String path = s.getAttributeValue("path");
String dirLocation = s.getAttributeValue("location");
if (dirLocation == null)
dirLocation = s.getAttributeValue("dirLocation");
dirLocation = expandAliasForPath(dirLocation);
if (path != null) {
if (path.charAt(0) == '/') path = path.substring(1);
int last = path.length() - 1;
if (path.charAt(last) == '/') path = path.substring(0, last);
}
if (dirLocation != null) {
int last = dirLocation.length() - 1;
if (dirLocation.charAt(last) != '/') dirLocation = dirLocation + '/';
}
return new DataRootConfig(path, dirLocation, s.getAttributeValue("cache"));
}
protected DateType readDate(Element elem) {
if (elem == null) return null;
String format = elem.getAttributeValue("format");
String type = elem.getAttributeValue("type");
return makeDateType(elem.getText(), format, type);
}
protected DateType makeDateType(String text, String format, String type) {
if (text == null) return null;
try {
return new DateType(text, format, type);
} catch (java.text.ParseException e) {
factory.appendErr(" ** Parse error: Bad date format = " + text + "\n");
return null;
}
}
protected TimeDuration readDuration(Element elem) {
if (elem == null) return null;
String text = null;
try {
text = elem.getText();
return new TimeDuration(text);
} catch (java.text.ParseException e) {
factory.appendErr(" ** Parse error: Bad duration format = " + text + "\n");
return null;
}
}
protected InvDocumentation readDocumentation(InvCatalog cat, Element s) {
String href = s.getAttributeValue("href", xlinkNS);
String title = s.getAttributeValue("title", xlinkNS);
String type = s.getAttributeValue("type"); // not XLink type
String content = s.getTextNormalize();
URI uri = null;
if (href != null) {
try {
uri = cat.resolveUri(href);
} catch (Exception e) {
factory.appendErr(" ** Invalid documentation href = " + href + " " + e.getMessage() + "\n");
}
}
InvDocumentation doc = new InvDocumentation(href, uri, title, type, content);
// LOOK XHTML ?? !!
if (InvCatalogFactory.debugXML) System.out.println(" Documentation added: " + doc);
return doc;
}
protected double readDouble(Element elem) {
if (elem == null) return Double.NaN;
String text = elem.getText();
try {
return Double.parseDouble(text);
} catch (NumberFormatException e) {
factory.appendErr(" ** Parse error: Bad double format = " + text + "\n");
return Double.NaN;
}
}
protected ThreddsMetadata.GeospatialCoverage readGeospatialCoverage(Element gcElem) {
if (gcElem == null) return null;
String zpositive = gcElem.getAttributeValue("zpositive");
ThreddsMetadata.Range northsouth = readGeospatialRange(gcElem.getChild("northsouth", defNS), CDM.LAT_UNITS);
ThreddsMetadata.Range eastwest = readGeospatialRange(gcElem.getChild("eastwest", defNS), CDM.LON_UNITS);
ThreddsMetadata.Range updown = readGeospatialRange(gcElem.getChild("updown", defNS), "m");
// look for names
List names = new ArrayList<>();
java.util.List list = gcElem.getChildren("name", defNS);
for (Element e : list) {
ThreddsMetadata.Vocab name = readControlledVocabulary(e);
names.add(name);
}
return new ThreddsMetadata.GeospatialCoverage(eastwest, northsouth, updown, names, zpositive);
}
protected ThreddsMetadata.Range readGeospatialRange(Element spElem, String defUnits) {
if (spElem == null) return null;
double start = readDouble(spElem.getChild("start", defNS));
double size = readDouble(spElem.getChild("size", defNS));
double resolution = readDouble(spElem.getChild("resolution", defNS));
String units = spElem.getChildText("units", defNS);
if (units == null) units = defUnits;
return new ThreddsMetadata.Range(start, size, resolution, units);
}
protected InvMetadata readMetadata(InvCatalog catalog, InvDatasetImpl dataset, Element mdataElement) {
// there are 6 cases to deal with: threddsNamespace vs not & inline vs Xlink & hasConverter or not
// (the hasConverter only applies when its not threddsNamespace, giving 6 cases)
// this factory is the converter for threddsNamespace metadata
// and also handles non-threddsNamespace when there is no converter, in which case it just
// propagates the inline dom elements
// figure out the namespace
Namespace namespace;
List inlineElements = mdataElement.getChildren();
if (inlineElements.size() > 0) // look at the namespace of the children, if they exist
namespace = ((Element) inlineElements.get(0)).getNamespace();
else
namespace = mdataElement.getNamespace(); // will be thredds
String mtype = mdataElement.getAttributeValue("metadataType");
String href = mdataElement.getAttributeValue("href", xlinkNS);
String title = mdataElement.getAttributeValue("title", xlinkNS);
String inheritedS = mdataElement.getAttributeValue("inherited");
boolean inherited = (inheritedS != null) && inheritedS.equalsIgnoreCase("true");
boolean isThreddsNamespace = ((mtype == null) || mtype.equalsIgnoreCase("THREDDS")) &&
namespace.getURI().equals(XMLEntityResolver.CATALOG_NAMESPACE_10);
// see if theres a converter for it.
MetadataConverterIF metaConverter = factory.getMetadataConverter(namespace.getURI());
if (metaConverter == null) metaConverter = factory.getMetadataConverter(mtype);
if (metaConverter != null) {
if (debugMetadataRead) System.out.println("found factory for metadata type = " + mtype + " namespace = " +
namespace + "=" + metaConverter.getClass().getName());
// see if theres any inline content
Object contentObj;
if (inlineElements.size() > 0) {
contentObj = metaConverter.readMetadataContent(dataset, mdataElement);
return new InvMetadata(dataset, mtype, namespace.getURI(), namespace.getPrefix(),
inherited, false, metaConverter, contentObj);
} else { // otherwise it must be an Xlink; defer reading
return new InvMetadata(dataset, href, title, mtype, namespace.getURI(),
namespace.getPrefix(), inherited, false, metaConverter);
}
}
// the case where its not ThreddsMetadata, but theres no converter
if (!isThreddsNamespace) {
if (inlineElements.size() > 0) {
// just hold onto the jdom elements as the "content" LOOK should be DOM?
return new InvMetadata(dataset, mtype, namespace.getURI(), namespace.getPrefix(),
inherited, false, this, mdataElement);
} else { // otherwise it must be an Xlink, never read
return new InvMetadata(dataset, href, title, mtype, namespace.getURI(),
namespace.getPrefix(), inherited, false, null);
}
}
// the case where its ThreddsMetadata
if (inlineElements.size() > 0) {
ThreddsMetadata tmg = new ThreddsMetadata(false);
readThreddsMetadata(catalog, dataset, mdataElement, tmg);
return new InvMetadata(dataset, mtype, namespace.getURI(), namespace.getPrefix(),
inherited, true, this, tmg);
} else { // otherwise it must be an Xlink; defer reading
return new InvMetadata(dataset, href, title, mtype, namespace.getURI(),
namespace.getPrefix(), inherited, true, this);
}
}
/* MetadataConverterIF */
public Object readMetadataContent(InvDataset dataset, org.jdom2.Element mdataElement) {
InvMetadata m = readMetadata(dataset.getParentCatalog(), (InvDatasetImpl) dataset, mdataElement);
return m.getThreddsMetadata();
}
private SAXBuilder saxBuilder;
private Element readContentFromURL(java.net.URI uri) throws java.io.IOException {
if (saxBuilder == null) saxBuilder = new SAXBuilder();
Document doc;
try {
doc = saxBuilder.build(uri.toURL());
} catch (JDOMException e) {
throw new IOException(e.getMessage());
}
return doc.getRootElement();
}
// this is only called for ThredddsMetadata
public Object readMetadataContentFromURL(InvDataset dataset, java.net.URI uri) throws java.io.IOException {
Element elem = readContentFromURL(uri);
Object contentObject = readMetadataContent(dataset, elem);
if (debugMetadataRead) System.out.println(" convert to " + contentObject.getClass().getName());
return contentObject;
}
/* open and read the referenced catalog XML
if (debugMetadataRead) System.out.println(" readMetadataContentFromURL = " + url);
org.w3c.dom.Element mdataElement = factory.readOtherXML( url);
if (mdataElement == null) {
factory.appendErr(" ** failed to read thredds metadata at = "+url+" for dataset"+dataset.getName()+"\n");
return null;
}
Object contentObject = readMetadataContent( dataset, mdataElement);
if (debugMetadataRead) System.out.println(" convert to " + contentObject.getClass().getName());
return contentObject; */
// dummy LOOK
public boolean validateMetadataContent(Object contentObject, StringBuilder out) {
return true;
}
public void addMetadataContent(org.jdom2.Element mdataElement, Object contentObject) {
}
protected InvProperty readProperty(Element s) {
String name = s.getAttributeValue("name");
String value = s.getAttributeValue("value");
return new InvProperty(name, value);
}
protected ThreddsMetadata.Source readSource(Element elem) {
if (elem == null) return null;
ThreddsMetadata.Vocab name = readControlledVocabulary(elem.getChild("name", defNS));
Element contact = elem.getChild("contact", defNS);
if (contact == null) {
factory.appendErr(" ** Parse error: Missing contact element in = " + elem.getName() + "\n");
return null;
}
return new ThreddsMetadata.Source(name, contact.getAttributeValue("url"), contact.getAttributeValue("email"));
}
protected InvService readService(Element s, URI baseURI) {
String name = s.getAttributeValue("name");
String type = s.getAttributeValue("serviceType");
String serviceBase = s.getAttributeValue("base");
String suffix = s.getAttributeValue("suffix");
String desc = s.getAttributeValue("desc");
InvService service = new InvService(name, type, serviceBase, suffix, desc);
java.util.List propertyList = s.getChildren("property", defNS);
for (Element e : propertyList) {
InvProperty p = readProperty(e);
service.addProperty(p);
}
java.util.List rootList = s.getChildren("datasetRoot", defNS);
for (Element e : rootList) {
InvProperty root = readDatasetRoot(e);
service.addDatasetRoot(root);
}
// nested services
java.util.List serviceList = s.getChildren("service", defNS);
for (Element e : serviceList) {
InvService ss = readService(e, baseURI);
service.addService(ss);
}
if (InvCatalogFactory.debugXML) System.out.println(" Service added: " + service);
return service;
}
protected double readDataSize(Element parent) {
Element elem = parent.getChild("dataSize", defNS);
if (elem == null) return Double.NaN;
double size;
String sizeS = elem.getText();
try {
size = Double.parseDouble(sizeS);
} catch (NumberFormatException e) {
factory.appendErr(" ** Parse error: Bad double format in size element = " + sizeS + "\n");
return Double.NaN;
}
String units = elem.getAttributeValue("units");
char c = Character.toUpperCase(units.charAt(0));
if (c == 'K') size *= 1000;
else if (c == 'M') size *= 1000 * 1000;
else if (c == 'G') size *= 1000 * 1000 * 1000;
else if (c == 'T') size *= 1000.0 * 1000 * 1000 * 1000;
else if (c == 'P') size *= 1000.0 * 1000 * 1000 * 1000 * 1000;
return size;
}
protected DateRange readTimeCoverage(Element tElem) {
if (tElem == null) return null;
DateType start = readDate(tElem.getChild("start", defNS));
DateType end = readDate(tElem.getChild("end", defNS));
TimeDuration duration = readDuration(tElem.getChild("duration", defNS));
TimeDuration resolution = readDuration(tElem.getChild("resolution", defNS));
try {
return new DateRange(start, end, duration, resolution);
} catch (java.lang.IllegalArgumentException e) {
factory.appendWarning(" ** warning: TimeCoverage error = " + e.getMessage() + "\n");
return null;
}
}
protected void readThreddsMetadata(InvCatalog catalog, InvDatasetImpl dataset, Element parent, ThreddsMetadata tmg) {
List list;
// look for creators - kind of a Source
list = parent.getChildren("creator", defNS);
for (Element e : list) {
tmg.addCreator(readSource(e));
}
// look for contributors
list = parent.getChildren("contributor", defNS);
for (Element e : list) {
tmg.addContributor(readContributor(e));
}
// look for dates
list = parent.getChildren("date", defNS);
for (Element e : list) {
DateType d = readDate(e);
tmg.addDate(d);
}
// look for documentation
list = parent.getChildren("documentation", defNS);
for (Element e : list) {
InvDocumentation doc = readDocumentation(catalog, e);
tmg.addDocumentation(doc);
}
// look for keywords - kind of a controlled vocabulary
list = parent.getChildren("keyword", defNS);
for (Element e : list) {
tmg.addKeyword(readControlledVocabulary(e));
}
// look for metadata
java.util.List mList = parent.getChildren("metadata", defNS);
for (Element e : mList) {
InvMetadata m = readMetadata(catalog, dataset, e);
if (m != null) {
tmg.addMetadata(m);
}
}
// look for projects - kind of a controlled vocabulary
list = parent.getChildren("project", defNS);
for (Element e : list) {
tmg.addProject(readControlledVocabulary(e));
}
// look for properties
list = parent.getChildren("property", defNS);
for (Element e : list) {
InvProperty p = readProperty(e);
tmg.addProperty(p);
}
// look for publishers - kind of a Source
list = parent.getChildren("publisher", defNS);
for (Element e : list) {
tmg.addPublisher(readSource(e));
}
// look for variables
list = parent.getChildren("variables", defNS);
for (Element e : list) {
ThreddsMetadata.Variables vars = readVariables(catalog, dataset, e);
tmg.addVariables(vars);
}
// can only be one each of these kinds
ThreddsMetadata.GeospatialCoverage gc = readGeospatialCoverage(parent.getChild("geospatialCoverage", defNS));
if (gc != null) tmg.setGeospatialCoverage(gc);
DateRange tc = readTimeCoverage(parent.getChild("timeCoverage", defNS));
if (tc != null) tmg.setTimeCoverage(tc);
Element serviceNameElem = parent.getChild("serviceName", defNS);
if (serviceNameElem != null) tmg.setServiceName(serviceNameElem.getText());
Element authElem = parent.getChild("authority", defNS);
if (authElem != null) tmg.setAuthority(authElem.getText());
Element dataTypeElem = parent.getChild("dataType", defNS);
if (dataTypeElem != null) {
String dataTypeName = dataTypeElem.getText();
if ((dataTypeName != null) && (dataTypeName.length() > 0)) {
FeatureType dataType = FeatureType.getType(dataTypeName.toUpperCase());
if (dataType == null) {
factory.appendWarning(" ** warning: non-standard data type = " + dataTypeName + "\n");
}
tmg.setDataType(dataType);
}
}
Element dataFormatElem = parent.getChild("dataFormat", defNS);
if (dataFormatElem != null) {
String dataFormatTypeName = dataFormatElem.getText();
if ((dataFormatTypeName != null) && (dataFormatTypeName.length() > 0)) {
DataFormatType dataFormatType = DataFormatType.findType(dataFormatTypeName);
if (dataFormatType == null) {
dataFormatType = DataFormatType.getType(dataFormatTypeName);
factory.appendWarning(" ** warning: non-standard dataFormat type = " + dataFormatTypeName + "\n");
}
tmg.setDataFormatType(dataFormatType);
}
}
double size = readDataSize(parent);
if (!Double.isNaN(size))
tmg.setDataSize(size);
}
protected ThreddsMetadata.Variable readVariable(Element varElem) {
if (varElem == null) return null;
String name = varElem.getAttributeValue("name");
String desc = varElem.getText();
String vocabulary_name = varElem.getAttributeValue("vocabulary_name");
String units = varElem.getAttributeValue("units");
String id = varElem.getAttributeValue("vocabulary_id");
return new ThreddsMetadata.Variable(name, desc, vocabulary_name, units, id);
}
protected ThreddsMetadata.Variables readVariables(InvCatalog cat, InvDataset ds, Element varsElem) {
if (varsElem == null) return null;
String vocab = varsElem.getAttributeValue("vocabulary");
String vocabHref = varsElem.getAttributeValue("href", xlinkNS);
URI vocabUri = null;
if (vocabHref != null) {
try {
vocabUri = cat.resolveUri(vocabHref);
} catch (Exception e) {
factory.appendErr(" ** Invalid Variables vocabulary URI = " + vocabHref + " " + e.getMessage() + "\n");
}
}
java.util.List vlist = varsElem.getChildren("variable", defNS);
String mapHref = null;
URI mapUri = null;
Element map = varsElem.getChild("variableMap", defNS);
if (map != null) {
mapHref = map.getAttributeValue("href", xlinkNS);
try {
mapUri = cat.resolveUri(mapHref);
} catch (Exception e) {
factory.appendErr(" ** Invalid Variables map URI = " + mapHref + " " + e.getMessage() + "\n");
}
}
if ((mapUri != null) && vlist.size() > 0) { // cant do both
factory.appendErr(" ** Catalog error: cant have variableMap and variable in same element (dataset = " +
ds.getName() + "\n");
mapUri = null;
}
ThreddsMetadata.Variables variables = new ThreddsMetadata.Variables(vocab, vocabHref, vocabUri, mapHref, mapUri);
for (Element e : vlist) {
ThreddsMetadata.Variable v = readVariable(e);
variables.addVariable(v);
}
// read in variable map LOOK: would like to defer
if (mapUri != null) {
Element varsElement;
try {
varsElement = readContentFromURL(mapUri);
List list = varsElement.getChildren("variable", defNS);
for (Element e : list) {
ThreddsMetadata.Variable v = readVariable(e);
variables.addVariable(v);
}
} catch (IOException e) {
logger.warn("Failure reading vaiable mapUri ", e);
}
/*org.w3c.dom.Element domElement = factory.readOtherXML(mapUri);
if (domElement != null) {
Element varsElement = toJDOM(domElement);
List list = varsElement.getChildren("variable", defNS);
for (int j = 0; j < list.size(); j++) {
ThreddsMetadata.Variable v = readVariable( (Element) list.get(j));
variables.addVariable(v);
}
} */
}
return variables;
}
/************************************************************************/
// Writing XML from objects
/**
* Write the catalog as an XML document to the specified stream.
*
* @param catalog write this catalog
* @param os write to this OutputStream
* @param raw write raw file if true (for server configuration)
* @throws IOException
*/
public void writeXML(InvCatalogImpl catalog, OutputStream os, boolean raw) throws IOException {
this.raw = raw;
writeXML(catalog, os);
this.raw = false;
}
private boolean raw = false;
/**
* Write the catalog as an XML document to the specified stream.
*
* @param catalog write this catalog
* @param os write to this OutputStream
* @throws IOException
*/
public void writeXML(InvCatalogImpl catalog, OutputStream os) throws IOException {
// Output the document, use standard formatter
//XMLOutputter fmt = new XMLOutputter();
//fmt.setNewlines(true);
//fmt.setIndent(" ");
//fmt.setTrimAllWhite( true);
XMLOutputter fmt = new XMLOutputter(org.jdom2.output.Format.getPrettyFormat()); // LOOK maybe compact ??
fmt.output(writeCatalog(catalog), os);
}
public Document writeCatalog(InvCatalogImpl cat) {
Element rootElem = new Element("catalog", defNS);
Document doc = new Document(rootElem);
// attributes
if (cat.getName() != null)
rootElem.setAttribute("name", cat.getName());
rootElem.setAttribute("version", version);
rootElem.addNamespaceDeclaration(xlinkNS);
if (cat.getExpires() != null)
rootElem.setAttribute("expires", cat.getExpires().toString());
// services
Iterator iter = cat.getServices().iterator();
while (iter.hasNext()) {
InvService service = (InvService) iter.next();
rootElem.addContent(writeService(service));
}
// dataset roots
if (raw) {
iter = cat.getDatasetRoots().iterator();
while (iter.hasNext()) {
InvProperty p = (InvProperty) iter.next();
rootElem.addContent(writeDatasetRoot(p));
}
}
// properties
iter = cat.getProperties().iterator();
while (iter.hasNext()) {
InvProperty p = (InvProperty) iter.next();
rootElem.addContent(writeProperty(p));
}
// datasets
iter = cat.getDatasets().iterator();
while (iter.hasNext()) {
InvDatasetImpl ds = (InvDatasetImpl) iter.next();
if (ds instanceof InvDatasetScan)
rootElem.addContent(writeDatasetScan((InvDatasetScan) ds));
else if (ds instanceof InvCatalogRef)
rootElem.addContent(writeCatalogRef((InvCatalogRef) ds));
else
rootElem.addContent(writeDataset(ds));
}
return doc;
}
private Element writeAccess(InvAccessImpl access) {
Element accessElem = new Element("access", defNS);
accessElem.setAttribute("urlPath", access.getUrlPath());
if (access.getServiceName() != null)
accessElem.setAttribute("serviceName", access.getServiceName());
if (access.getDataFormatType() != null)
accessElem.setAttribute("dataFormat", access.getDataFormatType().toString());
if (access.hasDataSize())
accessElem.addContent(writeDataSize(access.getDataSize()));
return accessElem;
}
private Element writeCatalogRef(InvCatalogRef catRef) {
Element catrefElem = new Element("catalogRef", defNS);
catrefElem.setAttribute("href", catRef.getXlinkHref(), xlinkNS);
String name = catRef.getName() == null ? "" : catRef.getName();
catrefElem.setAttribute("title", name, xlinkNS);
if (catRef.getID() != null)
catrefElem.setAttribute("ID", catRef.getID());
if (catRef.getRestrictAccess() != null)
catrefElem.setAttribute("restrictAccess", catRef.getRestrictAccess());
catrefElem.setAttribute("name", "");
/* List list = catRef.getDocumentation();
for (int j=0; j< list.size(); j++) {
InvDocumentation doc = (InvDocumentation) list.get(j);
catrefElem.addContent( writeDocumentation(doc, "documentation"));
} */
return catrefElem;
}
protected Element writeContributor(ThreddsMetadata.Contributor c) {
Element elem = new Element("contributor", defNS);
if (c.getRole() != null)
elem.setAttribute("role", c.getRole());
elem.setText(c.getName());
return elem;
}
private Element writeControlledVocabulary(ThreddsMetadata.Vocab v, String name) {
Element elem = new Element(name, defNS);
if (v.getVocabulary() != null)
elem.setAttribute("vocabulary", v.getVocabulary());
elem.addContent(v.getText());
return elem;
}
private Element writeDataset(InvDatasetImpl ds) {
Element dsElem = new Element("dataset", defNS);
if (ds instanceof InvDatasetImplProxy) {
dsElem.setAttribute("name", ((InvDatasetImplProxy) ds).getAliasName());
dsElem.setAttribute("alias", ds.getID());
return dsElem;
}
writeDatasetInfo(ds, dsElem, true, raw);
return dsElem;
}
private Element writeDatasetRoot(InvProperty prop) {
Element drootElem = new Element("datasetRoot", defNS);
drootElem.setAttribute("path", prop.getName());
drootElem.setAttribute("location", prop.getValue());
return drootElem;
}
private Element writeDatasetScan(InvDatasetScan ds) {
Element dsElem;
if (raw) {
// Setup datasetScan element
dsElem = new Element("datasetScan", defNS);
writeDatasetInfo(ds, dsElem, false, true);
dsElem.setAttribute("path", ds.getPath());
dsElem.setAttribute("location", ds.getScanLocation());
// Write datasetConfig element
if (ds.getCrDsClassName() != null) {
Element configElem = new Element("crawlableDatasetImpl", defNS);
configElem.setAttribute("className", ds.getCrDsClassName());
if (ds.getCrDsConfigObj() != null) {
if (ds.getCrDsConfigObj() instanceof Element) {
configElem.addContent((Element) ds.getCrDsConfigObj());
}
}
}
// Write filter element
if (ds.getFilter() != null)
dsElem.addContent(writeDatasetScanFilter(ds.getFilter()));
// Write addID element
//if ( ds.getIdentifier() != null )
dsElem.addContent(writeDatasetScanIdentifier(ds.getIdentifier()));
// Write namer element
if (ds.getNamer() != null)
dsElem.addContent(writeDatasetScanNamer(ds.getNamer()));
// Write sort element
if (ds.getSorter() != null)
dsElem.addContent(writeDatasetScanSorter(ds.getSorter()));
// Write addProxy element (and old addLatest element)
if (!ds.getProxyDatasetHandlers().isEmpty())
dsElem.addContent(writeDatasetScanAddProxies(ds.getProxyDatasetHandlers()));
// Write addDatasetSize element
if (ds.getAddDatasetSize())
dsElem.addContent(new Element("addDatasetSize", defNS));
// Write addTimeCoverage and datasetEnhancerImpl elements
if (ds.getChildEnhancerList() != null)
dsElem.addContent(writeDatasetScanEnhancer(ds.getChildEnhancerList()));
// @todo Write catalogRefExpander elements
// if ( ds.getCatalogRefExpander() != null )
// dsElem.addContent( writeDatasetScanCatRefExpander( ds.getCatalogRefExpander()));
} else {
if (ds.isValid()) {
dsElem = new Element("catalogRef", defNS);
writeDatasetInfo(ds, dsElem, false, false);
dsElem.setAttribute("href", ds.getXlinkHref(), xlinkNS);
dsElem.setAttribute("title", ds.getName(), xlinkNS);
dsElem.setAttribute("name", "");
dsElem.addContent(writeProperty(new InvProperty("DatasetScan", "true")));
} else {
dsElem = new Element("dataset", defNS);
dsElem.setAttribute("name", "** Misconfigured DatasetScan <" + ds.getPath() + "> **");
dsElem.addContent(new Comment(ds.getInvalidMessage()));
}
}
return dsElem;
}
Element writeDatasetScanFilter(CrawlableDatasetFilter filter) {
Element filterElem = new Element("filter", defNS);
if (filter.getClass().isAssignableFrom(MultiSelectorFilter.class) && filter.getConfigObject() != null) {
for (Object o : ((List) filter.getConfigObject())) {
MultiSelectorFilter.Selector curSelector = (MultiSelectorFilter.Selector) o;
Element curSelectorElem;
if (curSelector.isIncluder())
curSelectorElem = new Element("include", defNS);
else
curSelectorElem = new Element("exclude", defNS);
CrawlableDatasetFilter curFilter = curSelector.getFilter();
if (curFilter instanceof WildcardMatchOnNameFilter) {
curSelectorElem.setAttribute("wildcard", ((WildcardMatchOnNameFilter) curFilter).getWildcardString());
curSelectorElem.setAttribute("atomic", curSelector.isApplyToAtomicDataset() ? "true" : "false");
curSelectorElem.setAttribute("collection", curSelector.isApplyToCollectionDataset() ? "true" : "false");
} else if (curFilter instanceof RegExpMatchOnNameFilter) {
curSelectorElem.setAttribute("regExp", ((RegExpMatchOnNameFilter) curFilter).getRegExpString());
curSelectorElem.setAttribute("atomic", curSelector.isApplyToAtomicDataset() ? "true" : "false");
curSelectorElem.setAttribute("collection", curSelector.isApplyToCollectionDataset() ? "true" : "false");
} else if (curFilter instanceof LastModifiedLimitFilter) {
curSelectorElem.setAttribute("lastModLimitInMillis", Long.toString(((LastModifiedLimitFilter) curFilter).getLastModifiedLimitInMillis()));
curSelectorElem.setAttribute("atomic", curSelector.isApplyToAtomicDataset() ? "true" : "false");
curSelectorElem.setAttribute("collection", curSelector.isApplyToCollectionDataset() ? "true" : "false");
} else
curSelectorElem.addContent(new Comment("Unknown selector type <" + curSelector.getClass().getName() + ">."));
filterElem.addContent(curSelectorElem);
}
} else {
filterElem.addContent(writeDatasetScanUserDefined("crawlableDatasetFilterImpl", filter.getClass().getName(), filter.getConfigObject()));
}
return filterElem;
}
private Element writeDatasetScanNamer(CrawlableDatasetLabeler namer) {
Element namerElem = null;
if (namer != null) {
namerElem = new Element("namer", defNS);
if (namer instanceof MultiLabeler) {
for (CrawlableDatasetLabeler curNamer : ((MultiLabeler) namer).getLabelerList()) {
Element curNamerElem;
if (curNamer instanceof RegExpAndReplaceOnNameLabeler) {
curNamerElem = new Element("regExpOnName", defNS);
curNamerElem.setAttribute("regExp", ((RegExpAndReplaceOnNameLabeler) curNamer).getRegExp());
curNamerElem.setAttribute("replaceString", ((RegExpAndReplaceOnNameLabeler) curNamer).getReplaceString());
namerElem.addContent(curNamerElem);
} else if (curNamer instanceof RegExpAndReplaceOnPathLabeler) {
curNamerElem = new Element("regExpOnPath", defNS);
curNamerElem.setAttribute("regExp", ((RegExpAndReplaceOnPathLabeler) curNamer).getRegExp());
curNamerElem.setAttribute("replaceString", ((RegExpAndReplaceOnPathLabeler) curNamer).getReplaceString());
namerElem.addContent(curNamerElem);
} else {
String tmpMsg = "writeDatasetScanNamer(): unsupported namer <" + curNamer.getClass().getName() + ">.";
logger.warn(tmpMsg);
namerElem.addContent(new Comment(tmpMsg));
}
}
} else {
namerElem.addContent(writeDatasetScanUserDefined("crawlableDatasetLabelerImpl", namer.getClass().getName(), namer.getConfigObject()));
}
}
return namerElem;
}
private Element writeDatasetScanIdentifier(CrawlableDatasetLabeler identifier) {
Element identifierElem = new Element("addID", defNS);
if (identifier != null) {
if (identifier instanceof SimpleLatestProxyDsHandler) {
return identifierElem;
} else {
identifierElem = new Element("addID", defNS);
identifierElem.addContent(writeDatasetScanUserDefined("crawlableDatasetLabelerImpl", identifier.getClass().getName(), identifier.getConfigObject()));
}
}
return identifierElem;
}
private Element writeDatasetScanAddProxies(Map proxyDsHandlers) {
Element addProxiesElem;
// Write addLatest element if only proxyDsHandler and named "latest.xml".
if (proxyDsHandlers.size() == 1 && proxyDsHandlers.containsKey("latest.xml")) {
Object o = proxyDsHandlers.get("latest.xml");
if (o instanceof SimpleLatestProxyDsHandler) {
SimpleLatestProxyDsHandler pdh = (SimpleLatestProxyDsHandler) o;
String name = pdh.getProxyDatasetName();
boolean top = pdh.isLocateAtTopOrBottom();
String serviceName = pdh.getProxyDatasetService(null).getName();
addProxiesElem = new Element("addLatest", defNS);
if (name.equals("latest.xml") && top && serviceName.equals("latest"))
return addProxiesElem;
else {
Element simpleLatestElem = new Element("simpleLatest", defNS);
simpleLatestElem.setAttribute("name", name);
simpleLatestElem.setAttribute("top", top ? "true" : "false");
simpleLatestElem.setAttribute("servicName", serviceName);
addProxiesElem.addContent(simpleLatestElem);
return addProxiesElem;
}
}
}
// Write "addProxies" element
addProxiesElem = new Element("addProxies", defNS);
for (Map.Entry entry : proxyDsHandlers.entrySet()) {
String curName = entry.getKey();
ProxyDatasetHandler curPdh = entry.getValue();
if (curPdh instanceof SimpleLatestProxyDsHandler) {
SimpleLatestProxyDsHandler sPdh = (SimpleLatestProxyDsHandler) curPdh;
Element simpleLatestElem = new Element("simpleLatest", defNS);
simpleLatestElem.setAttribute("name", sPdh.getProxyDatasetName());
simpleLatestElem.setAttribute("top", sPdh.isLocateAtTopOrBottom() ? "true" : "false");
simpleLatestElem.setAttribute("servicName", sPdh.getProxyDatasetService(null).getName());
addProxiesElem.addContent(simpleLatestElem);
} else if (curPdh instanceof LatestCompleteProxyDsHandler) {
LatestCompleteProxyDsHandler lcPdh = (LatestCompleteProxyDsHandler) curPdh;
Element latestElem = new Element("latestComplete", defNS);
latestElem.setAttribute("name", lcPdh.getProxyDatasetName());
latestElem.setAttribute("top", lcPdh.isLocateAtTopOrBottom() ? "true" : "false");
latestElem.setAttribute("servicName", lcPdh.getProxyDatasetService(null).getName());
latestElem.setAttribute("lastModifiedLimit", Long.toString(lcPdh.getLastModifiedLimit()));
addProxiesElem.addContent(latestElem);
} else {
logger.warn("writeDatasetScanAddProxies(): unknown type of ProxyDatasetHandler <" + curPdh.getProxyDatasetName() + ">.");
// latestAdderElem.addContent( writeDatasetScanUserDefined( "datasetInserterImpl", latestAdder.getClass().getName(), latestAdder.getConfigObject() ) );
}
}
return addProxiesElem;
}
private Element writeDatasetScanSorter(CrawlableDatasetSorter sorter) {
Element sorterElem = new Element("sort", defNS);
if (sorter instanceof LexigraphicByNameSorter) {
Element lexElem = new Element("lexigraphicByName", defNS);
lexElem.setAttribute("increasing", ((LexigraphicByNameSorter) sorter).isIncreasing() ? "true" : "false");
sorterElem.addContent(lexElem);
} else {
sorterElem.addContent(writeDatasetScanUserDefined("crawlableDatasetSorterImpl", sorter.getClass().getName(), sorter.getConfigObject()));
}
return sorterElem;
}
private List writeDatasetScanEnhancer(List enhancerList) {
List enhancerElemList = new ArrayList<>();
int timeCovCount = 0;
for (DatasetEnhancer curEnhancer : enhancerList) {
if (curEnhancer instanceof RegExpAndDurationTimeCoverageEnhancer) {
if (timeCovCount > 0) {
logger.warn("writeDatasetScanEnhancer(): More than one addTimeCoverage element, skipping.");
continue;
}
timeCovCount++;
Element timeCovElem = new Element("addTimeCoverage", defNS);
RegExpAndDurationTimeCoverageEnhancer timeCovEnhancer = (RegExpAndDurationTimeCoverageEnhancer) curEnhancer;
timeCovElem.setAttribute("datasetNameMatchPattern", timeCovEnhancer.getMatchPattern());
timeCovElem.setAttribute("startTimeSubstitutionPattern", timeCovEnhancer.getSubstitutionPattern());
timeCovElem.setAttribute("duration", timeCovEnhancer.getDuration());
enhancerElemList.add(timeCovElem);
} else {
enhancerElemList.add(writeDatasetScanUserDefined("datasetEnhancerImpl", curEnhancer.getClass().getName(), curEnhancer.getConfigObject()));
}
}
return enhancerElemList;
}
private Element writeDatasetScanUserDefined(String userDefName, String className, Object configObj) {
Element userDefElem = new Element(userDefName, defNS);
userDefElem.setAttribute("className", className);
if (configObj != null) {
if (configObj instanceof Element)
userDefElem.addContent((Element) configObj);
else
userDefElem.addContent(new Comment("This class <" + className + "> not yet supported. This XML is missing configuration information (of type " + configObj.getClass().getName() + ")."));
}
return userDefElem;
}
private void writeDatasetInfo(InvDatasetImpl ds, Element dsElem, boolean doNestedDatasets, boolean showNcML) {
dsElem.setAttribute("name", ds.getName());
// other attributes, note the others get made into an element
if ((ds.getCollectionType() != null) && (ds.getCollectionType() != CollectionType.NONE))
dsElem.setAttribute("collectionType", ds.getCollectionType().toString());
if (ds.isHarvest())
dsElem.setAttribute("harvest", "true");
if (ds.getID() != null)
dsElem.setAttribute("ID", ds.getID());
if (ds.getUrlPath() != null)
dsElem.setAttribute("urlPath", ds.getUrlPath());
if (ds.getRestrictAccess() != null)
dsElem.setAttribute("restrictAccess", ds.getRestrictAccess());
// services (local only)
for (InvService service : ds.getServicesLocal()) {
dsElem.addContent(writeService(service));
}
// thredds metadata
writeThreddsMetadata(dsElem, ds.getLocalMetadata());
writeInheritedMetadata(dsElem, ds.getLocalMetadataInheritable());
// writeInheritedMetadata( dsElem, ds.getCat6Metadata()); // LOOK can we get rid of this?
// access (local only)
for (InvAccess a : ds.getAccessLocal()) {
dsElem.addContent(writeAccess( (InvAccessImpl) a));
}
if (showNcML && ds.getNcmlElement() != null) {
org.jdom2.Element ncml = ds.getNcmlElement().clone();
ncml.detach();
dsElem.addContent(ncml);
}
if (!doNestedDatasets) return;
// nested datasets
for (InvDataset nested : ds.getDatasets()) {
if (nested instanceof InvDatasetScan)
dsElem.addContent(writeDatasetScan((InvDatasetScan) nested));
else if (nested instanceof InvCatalogRef)
dsElem.addContent(writeCatalogRef((InvCatalogRef) nested));
else
dsElem.addContent(writeDataset( (InvDatasetImpl) nested));
}
}
protected Element writeDate(String name, DateType date) {
Element dateElem = new Element(name, defNS);
dateElem.addContent(date.getText());
if (date.getType() != null)
dateElem.setAttribute("type", date.getType());
if (date.getFormat() != null)
dateElem.setAttribute("format", date.getFormat());
return dateElem;
}
private Element writeDocumentation(InvDocumentation doc, String name) {
Element docElem = new Element(name, defNS);
if (doc.getType() != null)
docElem.setAttribute("type", doc.getType());
if (doc.hasXlink()) {
docElem.setAttribute("href", doc.getXlinkHref(), xlinkNS);
if (!doc.getXlinkTitle().equals(doc.getURI().toString()))
docElem.setAttribute("title", doc.getXlinkTitle(), xlinkNS);
}
String inline = doc.getInlineContent();
if (inline != null)
docElem.addContent(inline);
return docElem;
}
public Element writeGeospatialCoverage(ThreddsMetadata.GeospatialCoverage gc) {
Element elem = new Element("geospatialCoverage", defNS);
if (gc.getZPositive().equals("down"))
elem.setAttribute("zpositive", gc.getZPositive());
if (gc.getNorthSouthRange() != null)
writeGeospatialRange(elem, new Element("northsouth", defNS), gc.getNorthSouthRange());
if (gc.getEastWestRange() != null)
writeGeospatialRange(elem, new Element("eastwest", defNS), gc.getEastWestRange());
if (gc.getUpDownRange() != null)
writeGeospatialRange(elem, new Element("updown", defNS), gc.getUpDownRange());
// serialize isGlobal
java.util.List names = gc.getNames();
ThreddsMetadata.Vocab global = new ThreddsMetadata.Vocab("global", null);
if (gc.isGlobal() && !names.contains(global)) {
names.add(global);
} else if (!gc.isGlobal() && names.contains(global)) {
names.remove(global);
}
for (ThreddsMetadata.Vocab name : names) {
elem.addContent(writeControlledVocabulary(name, "name"));
}
return elem;
}
private void writeGeospatialRange(Element parent, Element elem, ThreddsMetadata.Range r) {
if (r == null) return;
elem.addContent(new Element("start", defNS).setText(Double.toString(r.getStart())));
elem.addContent(new Element("size", defNS).setText(Double.toString(r.getSize())));
if (r.hasResolution())
elem.addContent(new Element("resolution", defNS).setText(Double.toString(r.getResolution())));
if (r.getUnits() != null)
elem.addContent(new Element("units", defNS).setText(r.getUnits()));
parent.addContent(elem);
}
private Element writeMetadata(InvMetadata mdata) {
Element mdataElem = new Element("metadata", defNS);
if (mdata.getMetadataType() != null)
mdataElem.setAttribute("metadataType", mdata.getMetadataType());
if (mdata.isInherited())
mdataElem.setAttribute("inherited", "true");
String ns = mdata.getNamespaceURI();
if ((ns != null) && !ns.equals(XMLEntityResolver.CATALOG_NAMESPACE_10)) {
Namespace mdataNS = Namespace.getNamespace(mdata.getNamespacePrefix(), ns);
mdataElem.addNamespaceDeclaration(mdataNS);
}
if (mdata.hasXlink()) {
mdataElem.setAttribute("href", mdata.getXlinkHref(), xlinkNS);
if (mdata.getXlinkTitle() != null)
mdataElem.setAttribute("title", mdata.getXlinkTitle(), xlinkNS);
} else if (mdata.getThreddsMetadata() != null) {
writeThreddsMetadata(mdataElem, mdata.getThreddsMetadata());
} else {
// inline non-thredds case
MetadataConverterIF converter = mdata.getConverter();
if ((converter != null) && mdata.getContentObject() != null) {
if (mdata.getContentObject() instanceof Element) { // special case
Element mdataOrg = (Element) mdata.getContentObject();
List children = mdataOrg.getChildren();
for (Element child : children) {
mdataElem.addContent( child.clone());
}
} else {
//org.w3c.dom.Element dome = toDOM(mdataElem);
converter.addMetadataContent(mdataElem, mdata.getContentObject());
//mdataElem = toJDOM(dome);
mdataElem.detach();
}
}
}
return mdataElem;
}
private Element writeProperty(InvProperty prop) {
Element propElem = new Element("property", defNS);
propElem.setAttribute("name", prop.getName());
propElem.setAttribute("value", prop.getValue());
return propElem;
}
protected Element writeSource(String elementName, ThreddsMetadata.Source p) {
Element elem = new Element(elementName, defNS);
elem.addContent(writeControlledVocabulary(p.getNameVocab(), "name"));
Element contact = new Element("contact", defNS);
if (p.getUrl() != null)
contact.setAttribute("url", p.getUrl());
if (p.getEmail() != null)
contact.setAttribute("email", p.getEmail());
elem.addContent(contact);
return elem;
}
private Element writeService(InvService service) {
Element serviceElem = new Element("service", defNS);
serviceElem.setAttribute("name", service.getName());
serviceElem.setAttribute("serviceType", service.getServiceType().toString());
serviceElem.setAttribute("base", service.getBase());
if ((service.getSuffix() != null) && (service.getSuffix().length() > 0))
serviceElem.setAttribute("suffix", service.getSuffix());
// properties
for (InvProperty p : service.getProperties()) {
serviceElem.addContent(writeProperty(p));
}
// services
for (InvService nested : service.getServices()) {
serviceElem.addContent(writeService(nested));
}
// dataset roots
if (raw) {
for (InvProperty p : service.getDatasetRoots()) {
serviceElem.addContent(writeDatasetRoot(p));
}
}
return serviceElem;
}
private Element writeDataSize(double size) {
Element sizeElem = new Element("dataSize", defNS);
// want exactly the number of bytes
if (useBytesForDataSize) {
sizeElem.setAttribute("units", "bytes");
long bytes = (long) size;
sizeElem.setText(Long.toString(bytes));
return sizeElem;
}
// otherwise choose appropriate unit
String unit;
if (size > 1.0e15) {
unit = "Pbytes";
size *= 1.0e-15;
} else if (size > 1.0e12) {
unit = "Tbytes";
size *= 1.0e-12;
} else if (size > 1.0e9) {
unit = "Gbytes";
size *= 1.0e-9;
} else if (size > 1.0e6) {
unit = "Mbytes";
size *= 1.0e-6;
} else if (size > 1.0e3) {
unit = "Kbytes";
size *= 1.0e-3;
} else {
unit = "bytes";
}
sizeElem.setAttribute("units", unit);
sizeElem.setText(ucar.unidata.util.Format.d(size, 4));
return sizeElem;
}
/* protected void writeCat6InheritedMetadata( Element elem, ThreddsMetadata tmi) {
if ((tmi.getDataType() == null) && (tmi.getServiceName() == null) &&
(tmi.getAuthority() == null) && ( tmi.getProperties().size() == 0))
return;
Element mdataElem = new Element("metadata", defNS);
mdataElem.setAttribute("inherited", "true");
writeThreddsMetadata( mdataElem, tmi);
elem.addContent( mdataElem);
} */
protected void writeInheritedMetadata(Element elem, ThreddsMetadata tmi) {
Element mdataElem = new Element("metadata", defNS);
mdataElem.setAttribute("inherited", "true");
writeThreddsMetadata(mdataElem, tmi);
if (mdataElem.getChildren().size() > 0)
elem.addContent(mdataElem);
}
protected void writeThreddsMetadata(Element elem, ThreddsMetadata tmg) {
if (tmg.getServiceName() != null) {
Element serviceNameElem = new Element("serviceName", defNS);
serviceNameElem.setText(tmg.getServiceName());
elem.addContent(serviceNameElem);
}
if (tmg.getAuthority() != null) {
Element authElem = new Element("authority", defNS);
authElem.setText(tmg.getAuthority());
elem.addContent(authElem);
}
if ((tmg.getDataType() != null) && (tmg.getDataType() != FeatureType.NONE) && (tmg.getDataType() != FeatureType.ANY)) {
Element dataTypeElem = new Element("dataType", defNS);
dataTypeElem.setText(tmg.getDataType().toString());
elem.addContent(dataTypeElem);
}
if ((tmg.getDataFormatType() != null) && (tmg.getDataFormatType() != DataFormatType.NONE)) {
Element dataFormatElem = new Element("dataFormat", defNS);
dataFormatElem.setText(tmg.getDataFormatType().toString());
elem.addContent(dataFormatElem);
}
if (tmg.hasDataSize())
elem.addContent(writeDataSize(tmg.getDataSize()));
List docList = tmg.getDocumentation();
for (InvDocumentation doc : docList) {
elem.addContent(writeDocumentation(doc, "documentation"));
}
List contribList = tmg.getContributors();
for (ThreddsMetadata.Contributor c : contribList) {
elem.addContent(writeContributor(c));
}
List creatorList = tmg.getCreators();
for (ThreddsMetadata.Source p : creatorList) {
elem.addContent(writeSource("creator", p));
}
List kewordList = tmg.getKeywords();
for (ThreddsMetadata.Vocab v : kewordList) {
elem.addContent(writeControlledVocabulary(v, "keyword"));
}
List mdList = tmg.getMetadata();
for (InvMetadata m : mdList) {
elem.addContent(writeMetadata(m));
}
List projList = tmg.getProjects();
for (ThreddsMetadata.Vocab v : projList) {
elem.addContent(writeControlledVocabulary(v, "project"));
}
List propertyList = tmg.getProperties();
for (InvProperty p : propertyList) {
elem.addContent(writeProperty(p));
}
List pubList = tmg.getPublishers();
for (ThreddsMetadata.Source p : pubList) {
elem.addContent(writeSource("publisher", p));
}
List dateList = tmg.getDates();
for (DateType d : dateList) {
elem.addContent(writeDate("date", d));
}
ThreddsMetadata.GeospatialCoverage gc = tmg.getGeospatialCoverage();
if ((gc != null) && !gc.isEmpty())
elem.addContent(writeGeospatialCoverage(gc));
DateRange tc = tmg.getTimeCoverage();
if (tc != null)
elem.addContent(writeTimeCoverage(tc));
List varList = tmg.getVariables();
for (ThreddsMetadata.Variables v : varList) {
elem.addContent(writeVariables(v));
}
String varMapLink = tmg.getVariableMap();
if (varMapLink != null) {
Element velem = new Element("variableMap", defNS);
velem.setAttribute("href", varMapLink, xlinkNS);
velem.setAttribute("title", "variables", xlinkNS);
elem.addContent(velem);
}
}
protected Element writeTimeCoverage(DateRange t) {
Element elem = new Element("timeCoverage", defNS);
DateType start = t.getStart();
DateType end = t.getEnd();
TimeDuration duration = t.getDuration();
TimeDuration resolution = t.getResolution();
if (t.useStart() && (start != null) && !start.isBlank()) {
Element startElem = new Element("start", defNS);
startElem.setText(start.toString());
elem.addContent(startElem);
}
if (t.useEnd() && (end != null) && !end.isBlank()) {
Element telem = new Element("end", defNS);
telem.setText(end.toString());
elem.addContent(telem);
}
if (t.useDuration() && (duration != null) && !duration.isBlank()) {
Element telem = new Element("duration", defNS);
telem.setText(duration.toString());
elem.addContent(telem);
}
if (t.useResolution() && (resolution != null) && !resolution.isBlank()) {
Element telem = new Element("resolution", defNS);
telem.setText(t.getResolution().toString());
elem.addContent(telem);
}
return elem;
}
protected Element writeVariable(ThreddsMetadata.Variable v) {
Element elem = new Element("variable", defNS);
if (v.getName() != null)
elem.setAttribute("name", v.getName());
if (v.getDescription() != null) {
String desc = v.getDescription().trim();
if (desc.length() > 0)
elem.setText(v.getDescription());
}
if (v.getVocabularyName() != null)
elem.setAttribute("vocabulary_name", v.getVocabularyName());
if (v.getUnits() != null)
elem.setAttribute("units", v.getUnits());
String id = v.getVocabularyId();
if (id != null)
elem.setAttribute("vocabulary_id", id);
return elem;
}
protected Element writeVariables(ThreddsMetadata.Variables vs) {
Element elem = new Element("variables", defNS);
if (vs.getVocabulary() != null)
elem.setAttribute("vocabulary", vs.getVocabulary());
if (vs.getVocabHref() != null)
elem.setAttribute("href", vs.getVocabHref(), xlinkNS);
if (vs.getMapHref() != null) { // variable map
Element mapElem = new Element("variableMap", defNS);
mapElem.setAttribute("href", vs.getMapHref(), xlinkNS);
elem.addContent(mapElem);
} else { // inline variables
List varList = vs.getVariableList();
for (ThreddsMetadata.Variable v : varList) {
elem.addContent(writeVariable(v));
}
}
return elem;
}
/* public org.w3c.dom.Element toDOM( Element elem) {
try {
if (domOut == null) domOut = new DOMOutputter();
return domOut.output(elem);
} catch (JDOMException e) {
System.out.println("InvCatalogFactory6.readMetadata.toDom error " + e);
return null;
}
}
public Element toJDOM( org.w3c.dom.Element domElement) {
return builder.build(domElement);
} */
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy