package thredds.server.radarServer2; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.Namespace; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import ucar.nc2.constants.CDM; import ucar.nc2.units.DateRange; import ucar.nc2.units.DateType; import ucar.nc2.units.TimeDuration; import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.file.*; import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** * Handle configuration for the Radar Server */ public class RadarServerConfig { static ConcurrentHashMap<String, FileSystemProvider> fsproviders = new ConcurrentHashMap<>(); static public List<RadarConfigEntry> readXML(String filename) { List<RadarConfigEntry> configs = new ArrayList<>(); SAXBuilder builder = new SAXBuilder(); File f = new File(filename); try { Document doc = builder.build(f); Element cat = doc.getRootElement(); Namespace catNS = cat.getNamespace(); Element topDS = cat.getChild("dataset", cat.getNamespace()); for (Element dataset: topDS.getChildren("datasetScan", catNS)) { RadarConfigEntry conf = new RadarConfigEntry(); configs.add(conf); Element collection = dataset.getChild("radarCollection", catNS); conf.dateParseRegex = collection.getAttributeValue("dateRegex"); conf.dateFmt = collection.getAttributeValue("dateFormat"); conf.layout = collection.getAttributeValue("layout"); String crawlItems = collection.getAttributeValue("crawlItems"); if (crawlItems != null) { conf.crawlItems = Integer.parseInt(crawlItems); } else { conf.crawlItems = 5; } Element meta = dataset.getChild("metadata", catNS); conf.name = dataset.getAttributeValue("name"); conf.urlPath = dataset.getAttributeValue("path"); conf.dataPath = getPath(dataset.getAttributeValue("location")); conf.dataFormat = meta.getChild("dataFormat", catNS).getValue(); conf.stationFile = meta.getChild("stationFile", catNS).getAttributeValue("path"); conf.doc = meta.getChild("documentation", catNS).getValue(); conf.timeCoverage = readTimeCoverage( meta.getChild("timeCoverage", catNS)); conf.spatialCoverage = readGeospatialCoverage( meta.getChild("geospatialCoverage", catNS)); Element variables = meta.getChild("variables", catNS); conf.vars = new ArrayList<>(); for (Element var: variables.getChildren("variable", catNS)) { RadarConfigEntry.VarInfo inf = new RadarConfigEntry.VarInfo(); conf.vars.add(inf); inf.name = var.getAttributeValue("name"); inf.vocabName = var.getAttributeValue("vocabulary_name"); inf.units = var.getAttributeValue("units"); } } } catch (IOException | JDOMException e) { e.printStackTrace(); } return configs; } private static Path getPath(String location) throws IOException { FileSystem fs; // If we're given an actual URI, use that to find the file system. // Otherwise, use the default. if(location.contains(":")) { URI uri = URI.create(location); // Fix parsing of s3:// (note two '/') style paths if (uri.getPath().isEmpty()) { uri = URI.create(location.replace("//", "///")); } location = uri.getPath(); fs = getFS(uri); } else { fs = FileSystems.getDefault(); } return fs.getPath(location); } private static FileSystem getFS(URI uri) throws IOException { FileSystem fs; try { fs = getProvider(uri).getFileSystem(uri); } catch (ProviderNotFoundException e) { System.out.println("Provider not found: " + e.getMessage()); System.out.println("Using default file system."); fs = FileSystems.getDefault(); } return fs; } // This is to work around the fact that when we *get* a filesystem, we // cannot pass in the class loader. This results in custom providers (say // S3) not being found. However, the filesystem already exists, so the // filesystem can't be re-created either. private static FileSystemProvider getProvider(URI uri) throws IOException { if(fsproviders.containsKey(uri.getScheme())) { return fsproviders.get(uri.getScheme()); } else { FileSystem fs; try { fs = FileSystems.newFileSystem(uri, new HashMap<String, Object>(), Thread.currentThread().getContextClassLoader()); } catch (FileSystemAlreadyExistsException e) { fs = FileSystems.getFileSystem(uri); } fsproviders.put(uri.getScheme(), fs.provider()); return fs.provider(); } } protected static RadarConfigEntry.GeoInfo readGeospatialCoverage(Element gcElem) { if (gcElem == null) return null; Namespace defNS = gcElem.getNamespace(); RadarConfigEntry.GeoInfo gi = new RadarConfigEntry.GeoInfo(); gi.northSouth = readGeospatialRange(gcElem.getChild("northsouth", defNS), CDM.LAT_UNITS); gi.eastWest = readGeospatialRange(gcElem.getChild("eastwest", defNS), CDM.LON_UNITS); gi.upDown = readGeospatialRange(gcElem.getChild("updown", defNS), "m"); return gi; } protected static RadarConfigEntry.RangeInfo readGeospatialRange(Element spElem, String defUnits) { if (spElem == null) return null; Namespace defNS = spElem.getNamespace(); double start = readDouble(spElem.getChild("start", defNS)); double size = readDouble(spElem.getChild("size", defNS)); String units = spElem.getChildText("units", defNS); if (units == null) units = defUnits; RadarConfigEntry.RangeInfo ri = new RadarConfigEntry.RangeInfo(); ri.units = units; ri.start = start; ri.size = size; return ri; } protected static double readDouble(Element elem) { if (elem == null) return Double.NaN; String text = elem.getText(); try { return Double.parseDouble(text); } catch (NumberFormatException e) { return Double.NaN; } } protected static DateRange readTimeCoverage(Element tElem) { if (tElem == null) return null; Namespace defNS = tElem.getNamespace(); 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) { return null; } } protected static 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 static 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) { return null; } } protected static TimeDuration readDuration(Element elem) { if (elem == null) return null; String text; try { text = elem.getText(); return new TimeDuration(text); } catch (java.text.ParseException e) { return null; } } static public class RadarConfigEntry { public Path dataPath; public String name, urlPath, dataFormat, stationFile, doc; public String dateParseRegex, dateFmt, layout; public DateRange timeCoverage; public GeoInfo spatialCoverage; public int crawlItems; public List<VarInfo> vars; static public class GeoInfo { RangeInfo eastWest, northSouth, upDown; } static public class RangeInfo { public String units; public double start, size; } static public class VarInfo { public String name, vocabName, units; } } }