diff --git a/src/main/java/edu/iris/dmc/Application.java b/src/main/java/edu/iris/dmc/Application.java index 152508e..185f17a 100644 --- a/src/main/java/edu/iris/dmc/Application.java +++ b/src/main/java/edu/iris/dmc/Application.java @@ -27,6 +27,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Properties; @@ -77,7 +79,8 @@ public static void main(String[] args) throws Exception { try { commandLine = CommandLine.parse(args); } catch (CommandLineParseException e) { - System.err.println(e.getMessage()); + System.err.println(e.getMessage()+ "\n"); + help(); System.exit(1); } Logger rootLogger = LogManager.getLogManager().getLogger(""); @@ -132,14 +135,22 @@ public void run() throws Exception { if (commandLine.output() != null) { outputFile = commandLine.output().toFile(); if (!outputFile.exists()) { - throw new IOException(String.format("File %s is not found!", commandLine.output().toString())); + outputFile.createNewFile(); + //throw new IOException(String.format("File %s is not found!", commandLine.output().toString())); } + + try (OutputStream outputStream = new FileOutputStream(outputFile)) { + run(input, "csv", outputStream, commandLine.ignoreRules(), commandLine.ignoreWarnings()); } - try (OutputStream outputStream = (outputFile != null) ? new FileOutputStream(outputFile) : System.out;) { - run(input, "csv", outputStream, commandLine.ignoreRules(), commandLine.ignoreWarnings()); + }else { + try (OutputStream outputStream = System.out;) { + run(input, "csv", outputStream, commandLine.ignoreRules(), commandLine.ignoreWarnings()); + } + } + } - + private void run(List input, String format, OutputStream outputStream, int[] ignoreRules, boolean ignoreWarnings) throws Exception { RuleEngineService ruleEngineService = new RuleEngineService(ignoreWarnings, ignoreRules); @@ -164,6 +175,7 @@ private FDSNStationXML read(Path path) throws Exception { throw new IOException(String.format("File %s does not exist. File is required!", file.getAbsoluteFile())); } try (InputStream is = new FileInputStream(file)) { + // This is where stationxml vs seed is decided. if (file.getName().toLowerCase().endsWith(".xml")) { return DocumentMarshaller.unmarshal(is); } else { @@ -211,9 +223,11 @@ public Volume load(InputStream inputStream) throws SeedException, IOException { private RuleResultPrintStream getOutputStream(String format, OutputStream outputStream) throws IOException { if (format == null || format.isEmpty() || "html".equalsIgnoreCase(format)) { - return new HtmlPrintStream(outputStream); + return new CsvPrintStream(outputStream); } else if ("csv".equalsIgnoreCase(format)) { return new CsvPrintStream(outputStream); + } else if ("html".equalsIgnoreCase(format)) { + return new HtmlPrintStream(outputStream); } else if ("xml".equalsIgnoreCase(format)) { return new XmlPrintStream(outputStream); } else if ("report".equalsIgnoreCase(format)) { @@ -248,19 +262,47 @@ private static String center(String text, int length, String pad) { private static void printRules() { RuleEngineService ruleEngineService = new RuleEngineService(false, null); - for (Rule rule : ruleEngineService.getRules()) { + List ruleslist = ruleEngineService.getRules(); + Collections.sort(ruleslist, comparator); + System.out.println("Validator Rule Set:\n"); + System.out.println("--------------------------------------------------------------------------"); + for (Rule rule : ruleslist) { System.out.printf("%-8s %s%n", rule.getId(), rule.getDescription()); } + System.out.println("--------------------------------------------------------------------------"); + } + + private static Comparator comparator = new Comparator() { + public int compare(Rule c1, Rule c2) { + + int r = Integer.compare(c1.getId(), c2.getId()); + + return r; + } + }; private static void printUnits() { - System.out.println("UNIT TABLE:"); - System.out.println("-------------------------------------"); - for (String unit : UnitTable.units) { - System.out.println(unit); + System.out.println("Table of Acceptable Units:\n"); + + System.out.println("--------------------------------------------------------------------------"); + + List unitlist = UnitTable.units; + int stride = (unitlist.size()/4); + for (int row = 0; row < unitlist.size()/4; row++) { + System.out.println(String.format("%15s %15s %15s %15s", + unitlist.get(row), unitlist.get(row + stride), + unitlist.get(row + stride * 2), unitlist.get(row + stride * 3))); } + + + //for (String unit : UnitTable.units) { + // System.out.println(); - } + //} + System.out.println("--------------------------------------------------------------------------"); + +} private static void help() throws IOException { String version = "Version " + getVersion(); @@ -273,12 +315,13 @@ private static void help() throws IOException { System.out.println("Usage:"); System.out.println("java -jar stationxml-validator [OPTIONS]"); System.out.println("OPTIONS"); - System.out.println(" --output : where to output result, default is System.out"); - System.out.println(" --ignore-warnings: don't show warnings"); - System.out.println(" --rules : print a list of validation rules"); - System.out.println(" --units : print a list of units used to validate"); - System.out.println(" --debug :"); - System.out.println(" --help : print this message"); + System.out.println(" --file : Full input file path"); + System.out.println(" --output : where to output result, default is System.out"); + System.out.println(" --ignore-warnings : don't show warnings"); + System.out.println(" --rules : print a list of validation rules"); + System.out.println(" --units : print a list of units used to validate"); + System.out.println(" --debug : Change the verobsity level to debug"); + System.out.println(" --help : print this message"); System.out.println("==============================================================="); System.exit(0); } diff --git a/src/main/java/edu/iris/dmc/CommandLine.java b/src/main/java/edu/iris/dmc/CommandLine.java index 683c0d1..8966d9c 100644 --- a/src/main/java/edu/iris/dmc/CommandLine.java +++ b/src/main/java/edu/iris/dmc/CommandLine.java @@ -62,36 +62,50 @@ public boolean showUnits() { public Level getLogLevel() { return logLevel; } - public static CommandLine parse(String[] args) throws CommandLineParseException { + CommandLine commandLine = new CommandLine(); + if (args == null || args.length == 0) { throw new CommandLineParseException("Application arguments cannot be empty or null!"); + } - CommandLine commandLine = new CommandLine(); // look for showHelp or showVersion flags if (args.length == 1) { if ("--help".equalsIgnoreCase(args[0]) || "--showhelp".equalsIgnoreCase(args[0]) || "-h".equalsIgnoreCase(args[0])) { commandLine.showHelp = true; + return commandLine; } else if ("--version".equalsIgnoreCase(args[0]) || "-v".equalsIgnoreCase(args[0])) { commandLine.showVersion = true; + return commandLine; + } else if ("--units".equalsIgnoreCase(args[0]) || "-u".equalsIgnoreCase(args[0])) { + commandLine.showUnits = true; + return commandLine; + } else if ("--rules".equalsIgnoreCase(args[0]) || "-r".equalsIgnoreCase(args[0])) { + commandLine.showRules = true; + return commandLine; + } else { + String path = args[0]; + commandLine.file = Paths.get(path); + if (!commandLine.file.toFile().exists()) { + commandLine.showHelp = true; + System.out.println(String.format("File %s does not exist!", path)); + return commandLine; + + } } - return commandLine; + } if (args.length < 1) { throw new CommandLineParseException( - "Invalid number of arguments, expected at least 1 but was " + args.length + "!"); + "Invalid number of arguments, expected 1 but was " + args.length + "!"); } - String path = args[0]; - commandLine.file = Paths.get(path); - if (!commandLine.file.toFile().exists()) { - throw new CommandLineParseException(String.format("File %s does not exist!", path)); - } + // look for logLevel - if (args.length > 2) { - for (int i = 1; i < args.length; i++) { + if (args.length >= 2) { + for (int i = 0; i < args.length; i++) { String arg = args[i]; if ("--help".equalsIgnoreCase(arg) || "--showhelp".equalsIgnoreCase(arg) || "-h".equalsIgnoreCase(arg)) { @@ -105,17 +119,42 @@ public static CommandLine parse(String[] args) throws CommandLineParseException } else if ("--ignore-warnings".equalsIgnoreCase(arg)) { commandLine.ignoreWarnings = true; } else if ("--ignore-rules".equalsIgnoreCase(arg)) { - String rules = args[i + 1]; - commandLine.ignoreRules = Stream.of(rules.split("\\s*,\\s*")).map(String::trim) - .map(Integer::parseInt).mapToInt(item -> item).toArray(); - i = i + 1; + if(args.length < (i+2)) { + throw new CommandLineParseException(String.format("Please provide rules to ignore.")); + }else { + String rules = args[i + 1]; + commandLine.ignoreRules = Stream.of(rules.split("\\s*,\\s*")).map(String::trim) + .map(Integer::parseInt).mapToInt(item -> item).toArray(); + i = i + 1; + } } else if ("--show-rules".equalsIgnoreCase(arg)) { commandLine.showRules = true; } else if ("--show-units".equalsIgnoreCase(arg)) { commandLine.showUnits = true; } else if ("--output".equalsIgnoreCase(arg) || "-o".equalsIgnoreCase(arg)) { - commandLine.output = Paths.get(args[i + 1]); + if(args.length < (i+2)) { + throw new CommandLineParseException(String.format("Please provide an argument for --output.")); + }else { + commandLine.output = Paths.get(args[i + 1]); i = i + 1; + } + }else if ("--file".equalsIgnoreCase(arg) || "-f".equalsIgnoreCase(arg)) { + if(args.length < (i+2)) { + throw new CommandLineParseException(String.format("Please provide an argument for --file.")); + }else { + String path = args[i+1]; + commandLine.file = Paths.get(path); + i = i + 1; + if (!commandLine.file.toFile().exists()) { + throw new CommandLineParseException(String.format("File %s does not exist!", path)); + } + } + }else { + String path = args[i]; + commandLine.file = Paths.get(path); + if (!commandLine.file.toFile().exists()) { + throw new CommandLineParseException(String.format("File %s does not exist!", path)); + } } } diff --git a/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java b/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java index ebd0fc7..0ba7f32 100644 --- a/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java +++ b/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java @@ -26,6 +26,8 @@ import edu.iris.dmc.station.conditions.LocationCodeCondition; import edu.iris.dmc.station.conditions.MissingDecimationCondition; import edu.iris.dmc.station.conditions.OrientationCondition; +import edu.iris.dmc.station.conditions.OrientationConditionE; +import edu.iris.dmc.station.conditions.OrientationConditionZ; import edu.iris.dmc.station.conditions.PolesZerosCondition; import edu.iris.dmc.station.conditions.PolynomialCondition; import edu.iris.dmc.station.conditions.ResponseListCondition; @@ -68,16 +70,17 @@ private void init(int... ignoreRules) { defaultResponseRules(s); } + private void defaultNetworkRules(Set set) { String codeRegex = "[A-Z0-9_\\*\\?]{1,2}"; if (!set.contains(101)) { add(101, new CodeCondition(true, codeRegex, - "Network:Code must be assigned a string consisting of 1-2 uppercase characters A-Z and or numeric characters 0-9."), + "Network:Code must be assigned a string consisting of 1-2 uppercase A-Z and numeric 0-9 characters."), Network.class); } if (!set.contains(110)) { add(110, new StartTimeCondition(true, - "Network:startDate must occur before Network:endDate if Network:endDate is available."), + "If Network:startDate is included then it must occur before Network:endDate if included."), Network.class); } if (!set.contains(111)) { @@ -87,7 +90,7 @@ private void defaultNetworkRules(Set set) { } if (!set.contains(112)) { add(112, new EpochRangeCondition(true, - "Network:Epoch must encompass all subordinate Station:Epoch [Epoch=startDate-endDate]"), + "Network:Epoch must encompass all subordinate Station:Epoch"), Network.class); } } @@ -96,13 +99,13 @@ private void defaultStationRules(Set set) { String codeRegex = "[A-Z0-9_\\*\\?]{1,5}"; if (!set.contains(201)) { add(201, new CodeCondition(true, codeRegex, - "Station:Code must be assigned a string consisting of 1-5 uppercase characters A-Z and or numeric characters 0-9."), + "Station:Code must be assigned a string consisting of 1-5 uppercase A-Z and numeric 0-9 characters."), Station.class); } if (!set.contains(210)) { add(210, new StartTimeCondition(true, - "Station:startDate is required and must occur before Station:endDate if Station:endDate is available."), + "Station:startDate must be included and must occur before Station:endDate if included."), Station.class); } if (!set.contains(211)) { @@ -112,7 +115,7 @@ private void defaultStationRules(Set set) { } if (!set.contains(221)) { add(212, new EpochRangeCondition(true, - "Station:Epoch must encompass all subordinate Channel:Epoch [Epoch=startDate-endDate]"), + "Station:Epoch must encompass all subordinate Channel:Epoch"), Station.class); } @@ -132,34 +135,46 @@ private void defaultChannelRules(Set set) { Restriction[] restrictions = new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }; if (!set.contains(301)) { add(301, new CodeCondition(true, codeRegex, - "Channel:Code must be assigned a string consisting of 3 uppercase characters A-Z and or numeric characters 0-9."), + "Channel:Code must be assigned a string consisting of 3 uppercase A-Z and numeric 0-9 characters."), Channel.class); } if (!set.contains(302)) { add(302, new LocationCodeCondition(true, "([A-Z0-9\\*\\ ]{0,2})?", - "Channel:locationCode must be unassigned or be assigned a string consisting of 0-2 uppercase characters A-Z and or numeric characters 0-9."), + "Channel:locationCode must be assigned a string consisting of 0-2 uppercase A-Z and numeric 0-9 characters OR 2 whitespace characters OR --."), Channel.class); } if (!set.contains(303)) { - add(303, new CalibrationUnitCondition(false, "Invalid Calibration unit is invalid"), Channel.class); + add(303, new CalibrationUnitCondition(false, "If CalibrationUnits are included then CalibrationUnits:Name must be assigned a value from the IRIS StationXML Unit dictionary, case inconsistencies trigger warnings."), Channel.class); } if (!set.contains(304)) { - add(304, new SensorCondition(true, "Channel:Sensor:Description cannot be null."), Channel.class); + add(304, new SensorCondition(true, "Channel:Sensor:Description must be included and assigned a string consisting of 1 <= case insensitive A-Z and numeric 0-9 characters."), Channel.class); } if (!set.contains(305)) { add(305, new SampleRateCondition(false, - "If Channel:SampleRate is NULL or 0 then Response information should not be included.", + "If Channel:SampleRate equals 0 or is not included then Response must not be included.", restrictions), Channel.class); } if (!set.contains(310)) { add(310, new StartTimeCondition(true, - "Channel:startDate is required and must occur before Channel:endDate if Channel:endDate is available."), + "Channel:startDate must be included and must occur before Channel:endDate if included."), Channel.class); } if (!set.contains(332)) { add(332, new OrientationCondition(true, - "Channel:Azimuth and or Channel:Dip do not correspond within 5 degrees of tolerance to last digit of orthogonal Channel:Code.", + "If Channel:Code[LAST]==N then Channel:Azimuth must be assigned (>=355.0 or <=5.0) or (>=175.0 and <=185.0) and Channel:Dip must be assigned (>=-5 AND <=5.0).", + new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }), Channel.class); + } + + if (!set.contains(333)) { + add(333, new OrientationConditionE(true, + "If Channel:Code[LAST]==E then Channel:Azimuth must be assigned (>=85.0 and <=95.0) or (>=265.0 and <=275.0) and Channel:Dip must be assigned (>=-5 and <=5.0).", + new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }), Channel.class); + } + + if (!set.contains(334)) { + add(334, new OrientationConditionZ(true, + "If Channel:Code[LAST]==Z then Channel:Azimuth must be assigned (>=355.0 or <=5.0) and Channel:Dip must be assigned (>=-85.0 and <=-90.0) or (>=85.0 and <=90.0).", new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }), Channel.class); } } @@ -170,59 +185,59 @@ private void defaultResponseRules(Set s) { if (!s.contains(401)) { add(401, new StageSequenceCondition(true, - "The 'number' attribute of Response::Stage element must start at 1 and be sequential", + "Stage:number must start at 1 and be sequential.", restrictions), Response.class); } if (!s.contains(402)) { add(402, new UnitCondition(true, - "Stage[N]:InputUnits:Name and/or Stage[N]:OutputUnits:Name are not defined in Unit name overview for IRIS StationXML validator.", + "Stage[N]:InputUnits:Name and Stage[N]:OutputUnits:Name must be assigned a value from the IRIS StationXML Unit dictionary, case inconsistencies trigger warnings.", restrictions), Response.class); } if (!s.contains(403)) { - add(403, new StageUnitCondition(true, "Stage[N]:InputUnits:Name must equal Stage[N-1]:OutputUnits:Name.", + add(403, new StageUnitCondition(true, "If length(Stage) > 1 then Stage[N]:InputUnits:Name must equal the previously assigned Stage[M]:OutputUnits:Name.", restrictions), Response.class); } if (!s.contains(404)) { add(404, new DigitalFilterCondition(true, - "Stage types FIR|Coefficient|PolesZeros with transfer function type Digital must include Decimation and StageGain elements.", + "If Stage[N]:PolesZeros:PzTransferFunctionType:Digital or Stage[N]:FIR or Stage[N]:Coefficients:CfTransferFunctionType:DIGITAL are included then Stage[N] must include Stage[N]:Decimation and Stage[N]:StageGain elements.", restrictions), Response.class); } if (!s.contains(405)) { add(405, new ResponseListCondition(true, - "Stage of type ResponseList cannot be the only stage available in a response.", + "Stage:ResponseList cannot be the only stage included in a response.", new ChannelCodeRestriction(), new ChannelTypeRestriction()), Response.class); } if (!s.contains(410)) { - add(410, new EmptySensitivityCondition(true, "InstrumentSensitivity:Value cannot be assigned 0 or Null.", + add(410, new EmptySensitivityCondition(true, "If InstrumentSensitivity is included then InstrumentSensitivity:Value must be assigned a double > 0.0 ", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), Response.class); } if (!s.contains(411)) { add(411, new FrequencyCondition(true, - "InstrumentSensitivity:Frequency must be less than Channel:SampleRate/2 [Nyquist Frequency].", + "If InstrumentSensitivity is included then InstrumentSensitivity:Frequency must be less than Channel:SampleRate/2 [Nyquist Frequency]. ", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), Response.class); } if (!s.contains(412)) { add(412, new StageGainProductCondition(true, - "InstrumentSensitivity:Value must equal the product of all StageGain:Value if all StageGain:Frequency are equal to InstrumentSensitivity:Frequency [Normalization Frequency]. ", + "InstrumentSensitivity:Value must equal the product of all StageGain:Value if all StageGain:Frequency are equal to InstrumentSensitivity:Frequency [Normalization Frequency].", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), Response.class); } if (!s.contains(413)) { - add(413, new StageGainNonZeroCondition(true, "StageGain:Value cannot be assigned 0 or Null.", + add(413, new StageGainNonZeroCondition(true, "Stage[1:N]:StageGain must be included and Stage[1:N]:StageGain:Value must be assigned a double > 0.0 and Stage[1:N]:StageGain:Frequency must be assigned a double.", new ChannelCodeRestriction(), new ResponsePolynomialRestriction(), new ChannelTypeRestriction()), Response.class); } if (!s.contains(414)) { add(414, new PolesZerosCondition(false, - "If Stage[N] of type PolesZeros contains a Zero where both Real and Imaginary components equal 0 then InstrumentSensitivity:Frequency cannot equal 0 and Stage[N]:StageGain:Frequency cannot equal 0.", + "If Stage[N]:PolesZeros contains Zero:Real==0 and Zero:Imaginary==0 then InstrumentSensitivity:Frequency cannot equal 0 and Stage[N]:StageGain:Frequency cannot equal 0.", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), Response.class); } if (!s.contains(415)) { add(415, new PolynomialCondition(false, - "Response must be defined as Response:InstrumentPolynomial if it contains any Stages defined as ResponseStage:Polynomial", + "Response must be of type Response:InstrumentPolynomial if a Polynomial stage exist.", new ChannelCodeRestriction(), new ChannelTypeRestriction()), Response.class); } if (!s.contains(420)) { @@ -233,18 +248,18 @@ private void defaultResponseRules(Set s) { } if (!s.contains(421)) { add(421, new DecimationSampleRateCondition(true, - "Stage[Final]:Decimation:InputSampleRate divided by Stage[Final]:Decimation:Factor must equal Channel:SampleRate.", + "Stage[LAST]:Decimation:InputSampleRate divided by Stage[LAST]:Decimation:Factor must equal Channel:SampleRate.", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), Response.class); } if (!s.contains(422)) { add(422, new DecimationCondition(true, - "Stage[N]:Decimation:InputSampleRate must equal Stage[N-1]:Decimation:InputSampleRate divided by Stage[N-1]:Decimation:Factor.", + "Stage[N]:Decimation:InputSampleRate must equal the previously assigned Stage[M]:Decimation:InputSampleRate divided by Stage[M]:Decimation:Factor.", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), Response.class); } } - + public void add(int id, Condition condition, Class clazz) { if (condition == null || clazz == null) { throw new IllegalArgumentException("Null condition|class is not permitted"); diff --git a/src/main/java/edu/iris/dmc/station/RuleEngineService.java b/src/main/java/edu/iris/dmc/station/RuleEngineService.java index a35fecd..8b1de6a 100644 --- a/src/main/java/edu/iris/dmc/station/RuleEngineService.java +++ b/src/main/java/edu/iris/dmc/station/RuleEngineService.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import edu.iris.dmc.fdsn.station.model.Channel; import edu.iris.dmc.fdsn.station.model.FDSNStationXML; @@ -80,7 +81,7 @@ public Map> executeNetworkRules(Network network) { } public Map> executeAllRules(Network network) { - Map> map = new HashMap<>(); + Map> map = new TreeMap<>(); if (network == null) { return map; } diff --git a/src/main/java/edu/iris/dmc/station/conditions/CodeCondition.java b/src/main/java/edu/iris/dmc/station/conditions/CodeCondition.java index 0ef33b9..bb8cbed 100644 --- a/src/main/java/edu/iris/dmc/station/conditions/CodeCondition.java +++ b/src/main/java/edu/iris/dmc/station/conditions/CodeCondition.java @@ -28,14 +28,14 @@ private Message run(BaseNodeType t) { if (!required) { return Result.success(); } - return Result.error( "Expected a value like" + this.regex + " but was null."); + return Result.error( "Expected a value like " + this.regex + " but was null."); } Pattern p = Pattern.compile(this.regex); Matcher m = p.matcher(code); if (!m.matches()) { - return Result.error( "Expected a value like" + this.regex + " but was " + t.getCode()); + return Result.error( "Expected a value like " + this.regex + " but was " + t.getCode()); } return Result.success(); } diff --git a/src/main/java/edu/iris/dmc/station/conditions/OrientationCondition.java b/src/main/java/edu/iris/dmc/station/conditions/OrientationCondition.java index eaaefb5..e334ca5 100644 --- a/src/main/java/edu/iris/dmc/station/conditions/OrientationCondition.java +++ b/src/main/java/edu/iris/dmc/station/conditions/OrientationCondition.java @@ -66,19 +66,7 @@ public Message evaluate(Channel channel) { if (array.length < 3) { return Result.success(); } - if ('E' == array[2]) { - if (azimuth < 95 && azimuth > 85 || azimuth < 275 && azimuth > 265) { - - } else { - valid = false; - messageBuilder.append("azimuth: ").append(azimuth).append(" "); - } - - if (dip > 5 || dip < -5) { - valid = false; - messageBuilder.append("dip: ").append(dip).append(" "); - } - } else if ('N' == array[2]) { + if ('N' == array[2]) { if (azimuth <= 5 && azimuth >= 0 || azimuth >= 355 && azimuth <= 360 || (azimuth <= 185 && azimuth >= 175)) { @@ -88,17 +76,6 @@ public Message evaluate(Channel channel) { } if (dip < 5 || dip > -5) { - } else { - valid = false; - messageBuilder.append("dip: ").append(dip).append(" "); - } - } else if ('Z' == array[2]) { - if (azimuth > 5 && azimuth < 355) { - valid = false; - messageBuilder.append("azimuth: ").append(azimuth).append(" "); - } - if (dip > -95 && dip < -85 || (dip > 85 && dip < 95)) { - } else { valid = false; messageBuilder.append("dip: ").append(dip).append(" "); @@ -112,4 +89,4 @@ public Message evaluate(Channel channel) { .warning("Invalid channel orientation: " + messageBuilder.toString() + " for " + channel.getCode()); } -} + } \ No newline at end of file diff --git a/src/main/java/edu/iris/dmc/station/conditions/OrientationConditionE.java b/src/main/java/edu/iris/dmc/station/conditions/OrientationConditionE.java new file mode 100644 index 0000000..ae71543 --- /dev/null +++ b/src/main/java/edu/iris/dmc/station/conditions/OrientationConditionE.java @@ -0,0 +1,91 @@ +package edu.iris.dmc.station.conditions; + +import java.util.Objects; + +import edu.iris.dmc.fdsn.station.model.Azimuth; +import edu.iris.dmc.fdsn.station.model.Channel; +import edu.iris.dmc.fdsn.station.model.Dip; +import edu.iris.dmc.fdsn.station.model.Network; +import edu.iris.dmc.fdsn.station.model.Station; +import edu.iris.dmc.station.restrictions.Restriction; +import edu.iris.dmc.station.rules.Message; +import edu.iris.dmc.station.rules.Result; + +public class OrientationConditionE extends AbstractCondition { + + private Restriction[] restrictions; + + public OrientationConditionE(boolean required, String description, Restriction[] restrictions) { + super(required, description); + this.restrictions = restrictions; + } + + @Override + public Message evaluate(Network network) { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Message evaluate(Station station) { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Message evaluate(Channel channel) { + Objects.requireNonNull(channel, "channel cannot be null"); + + String code = channel.getCode(); + if (code == null) { + return Result.success(); + } + code = code.trim(); + if (code.isEmpty() || code.length() < 3 || channel.getAzimuth() == null || channel.getDip() == null) { + return Result.success(); + } + + for (Restriction r : this.restrictions) { + if (r.qualifies(channel)) { + return Result.success(); + } + } + if (channel.getCode() == null || channel.getCode().trim().isEmpty() || channel.getAzimuth() == null + || channel.getDip() == null) { + return Result.success(); + } + + if (channel.getAzimuth().getValue() == null || channel.getDip().getValue() == null) { + return Result.success(); + } + char[] array = channel.getCode().toCharArray(); + + double azimuth = channel.getAzimuth().getValue(); + double dip = channel.getDip().getValue(); + + boolean valid = true; + StringBuilder messageBuilder = new StringBuilder(); + if (array.length < 3) { + return Result.success(); + } + if ('E' == array[2]) { + if (azimuth < 95 && azimuth > 85 || azimuth < 275 && azimuth > 265) { + + } else { + valid = false; + messageBuilder.append("azimuth: ").append(azimuth).append(" "); + } + + if (dip > 5 || dip < -5) { + valid = false; + messageBuilder.append("dip: ").append(dip).append(" "); + } + } + + + if (valid) { + return Result.success(); + } + return Result + .warning("Invalid channel orientation: " + messageBuilder.toString() + " for " + channel.getCode()); + + } +} \ No newline at end of file diff --git a/src/main/java/edu/iris/dmc/station/conditions/OrientationConditionZ.java b/src/main/java/edu/iris/dmc/station/conditions/OrientationConditionZ.java new file mode 100644 index 0000000..b723d25 --- /dev/null +++ b/src/main/java/edu/iris/dmc/station/conditions/OrientationConditionZ.java @@ -0,0 +1,89 @@ +package edu.iris.dmc.station.conditions; + +import java.util.Objects; + +import edu.iris.dmc.fdsn.station.model.Azimuth; +import edu.iris.dmc.fdsn.station.model.Channel; +import edu.iris.dmc.fdsn.station.model.Dip; +import edu.iris.dmc.fdsn.station.model.Network; +import edu.iris.dmc.fdsn.station.model.Station; +import edu.iris.dmc.station.restrictions.Restriction; +import edu.iris.dmc.station.rules.Message; +import edu.iris.dmc.station.rules.Result; + +public class OrientationConditionZ extends AbstractCondition { + + private Restriction[] restrictions; + + public OrientationConditionZ(boolean required, String description, Restriction[] restrictions) { + super(required, description); + this.restrictions = restrictions; + } + + @Override + public Message evaluate(Network network) { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Message evaluate(Station station) { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Message evaluate(Channel channel) { + Objects.requireNonNull(channel, "channel cannot be null"); + + String code = channel.getCode(); + if (code == null) { + return Result.success(); + } + code = code.trim(); + if (code.isEmpty() || code.length() < 3 || channel.getAzimuth() == null || channel.getDip() == null) { + return Result.success(); + } + + for (Restriction r : this.restrictions) { + if (r.qualifies(channel)) { + return Result.success(); + } + } + if (channel.getCode() == null || channel.getCode().trim().isEmpty() || channel.getAzimuth() == null + || channel.getDip() == null) { + return Result.success(); + } + + if (channel.getAzimuth().getValue() == null || channel.getDip().getValue() == null) { + return Result.success(); + } + char[] array = channel.getCode().toCharArray(); + + double azimuth = channel.getAzimuth().getValue(); + double dip = channel.getDip().getValue(); + + boolean valid = true; + StringBuilder messageBuilder = new StringBuilder(); + if (array.length < 3) { + return Result.success(); + } + if ('Z' == array[2]) { + if (azimuth >= 5 && azimuth <= 355) { + valid = false; + messageBuilder.append("azimuth: ").append(azimuth).append(" "); + } + if ((dip > -95 && dip < -85) || (dip > 85 && dip < 95)) { + + } else { + valid = false; + messageBuilder.append("dip: ").append(dip).append(" "); + } + } + + if (valid) { + return Result.success(); + } + return Result + .warning("Invalid channel orientation: " + messageBuilder.toString() + " for " + channel.getCode()); + + } +} \ No newline at end of file diff --git a/src/main/java/edu/iris/dmc/station/conditions/StartTimeCondition.java b/src/main/java/edu/iris/dmc/station/conditions/StartTimeCondition.java index 9f70ce4..518090c 100644 --- a/src/main/java/edu/iris/dmc/station/conditions/StartTimeCondition.java +++ b/src/main/java/edu/iris/dmc/station/conditions/StartTimeCondition.java @@ -42,14 +42,14 @@ public Message check(BaseNodeType node) { if (node instanceof Network) { return Result.success(); } else { - return Result.error("startDate is required for node:" + node.getCode()); + return Result.error("startDate is required for " + node.getCode()); } } - if (node.getEndDate() != null) { - if (!TimeUtil.isBefore(node.getStartDate(), node.getEndDate())) { - return Result - .error("startDate " + node.getStartDate() + " must occur before endDate " + node.getEndDate()); + if (node.getEndDate() != null && node.getStartDate() != null) { + if (!node.getStartDate().isBefore(node.getEndDate())) { + return Result.error( + "EndDate " + node.getEndDate() + " must be greater than Start Time " + node.getStartDate()); } } return Result.success(); diff --git a/src/main/java/edu/iris/dmc/station/conditions/UnitCondition.java b/src/main/java/edu/iris/dmc/station/conditions/UnitCondition.java index c42c325..5c231bd 100644 --- a/src/main/java/edu/iris/dmc/station/conditions/UnitCondition.java +++ b/src/main/java/edu/iris/dmc/station/conditions/UnitCondition.java @@ -62,7 +62,7 @@ public Message evaluate(Channel channel, Response response) { } Units[] units = getUnits(stage); if (units == null) { - nestedMessage.add(Result.error("stage [ null units for stage " + stage.getNumber().intValue() + "]")); + nestedMessage.add(Result.error("stage [null units for stage " + stage.getNumber().intValue() + "]")); } else { Units inputUnits = units[0]; Units outputUnits = units[1]; @@ -75,28 +75,52 @@ public Message evaluate(Channel channel, Response response) { if (!result) { result = UnitTable.containsCaseInsensitive(inputUnits.getName()); if (result) { + if (stage.getNumber().intValue() < 10 ) { + nestedMessage.add(Result.warning("[stage " + String.format("%02d", stage.getNumber().intValue()) + + "] invalid input units " + inputUnits.getName())); + }else { nestedMessage.add(Result.warning("[stage " + stage.getNumber().intValue() + "] invalid input units " + inputUnits.getName())); + } } else { - nestedMessage.add(Result.error("[stage " + stage.getNumber().intValue() + if (stage.getNumber().intValue() < 10 ) { + nestedMessage.add(Result.error("[stage " + String.format("%02d", stage.getNumber().intValue()) + "] invalid input units " + inputUnits.getName())); + }else { + nestedMessage.add(Result.error("[stage " + stage.getNumber().intValue() + + "] invalid input units " + inputUnits.getName())); + } } } } if (outputUnits == null || outputUnits.getName() == null) { + if (stage.getNumber().intValue() < 10 ) { nestedMessage.add( - Result.error("Output unit cannot be null [stage " + stage.getNumber().intValue() + "]")); + Result.error("Output unit cannot be null [stage " + String.format("%02d", stage.getNumber().intValue()) + "]")); + }else { + Result.error("Output unit cannot be null [stage " + stage.getNumber().intValue() + "]"); + } } else { boolean result = UnitTable.contains(outputUnits.getName()); if (!result) { result = UnitTable.containsCaseInsensitive(outputUnits.getName().toLowerCase()); if (result) { - nestedMessage.add(Result.warning("[stage " + stage.getNumber().intValue() + if (stage.getNumber().intValue() < 10 ) { + nestedMessage.add(Result.warning("[stage " + String.format("%02d",stage.getNumber().intValue()) + "] invalid output units " + outputUnits.getName())); + }else { + nestedMessage.add(Result.warning("[stage " + stage.getNumber().intValue() + + "] invalid output units " + outputUnits.getName())); + } } else { - nestedMessage.add(Result.error("[stage " + stage.getNumber().intValue() + if (stage.getNumber().intValue() < 10 ) { + nestedMessage.add(Result.error("[stage " + String.format("%02d", stage.getNumber().intValue()) + + "] invalid output units " + outputUnits.getName())); + }else { + nestedMessage.add(Result.error("[stage " + stage.getNumber().intValue() + "] invalid output units " + outputUnits.getName())); + } } } } diff --git a/src/main/java/edu/iris/dmc/station/io/CsvPrintStream.java b/src/main/java/edu/iris/dmc/station/io/CsvPrintStream.java index 9fb3f9a..64eeb3e 100644 --- a/src/main/java/edu/iris/dmc/station/io/CsvPrintStream.java +++ b/src/main/java/edu/iris/dmc/station/io/CsvPrintStream.java @@ -16,6 +16,8 @@ import edu.iris.dmc.station.rules.Warning; public class CsvPrintStream extends PrintStream implements RuleResultPrintStream { + // This class is not used to print out messages. Look at CSVMessageLogger + // to alter the validator output messages. private static final Object[] FILE_HEADER = { "Source", "RuleId", "Type", "Network", "Station", "Channel", "Location", "StartDate", "EndDate", "Message" }; @@ -23,8 +25,9 @@ public class CsvPrintStream extends PrintStream implements RuleResultPrintStream public CsvPrintStream(OutputStream out) throws IOException { super(out); - CSVFormat csvFileFormat = CSVFormat.DEFAULT.withRecordSeparator(System.lineSeparator()); + CSVFormat csvFileFormat = CSVFormat.EXCEL.withRecordSeparator(System.lineSeparator()); this.csvFilePrinter = new CSVPrinter(this, csvFileFormat); + //this.csvFilePrinter = new CSVPrinter(this, CSVFormat.EXCEL); } public void printHeader() throws IOException { @@ -80,7 +83,6 @@ public void print(String source, Message message) throws IOException { csvFilePrinter.printRecord(record); csvFilePrinter.flush(); } - } @Override diff --git a/src/main/java/edu/iris/dmc/station/rules/Message.java b/src/main/java/edu/iris/dmc/station/rules/Message.java index 383048e..e9f68eb 100644 --- a/src/main/java/edu/iris/dmc/station/rules/Message.java +++ b/src/main/java/edu/iris/dmc/station/rules/Message.java @@ -14,6 +14,7 @@ public interface Message { public void setNetwork(Network network); + public Network getNetwork(); public void setStation(Station station); @@ -27,4 +28,6 @@ public interface Message { public String getDescription(); public String getSource(); + } + diff --git a/src/main/java/edu/iris/dmc/station/rules/UnitTable.java b/src/main/java/edu/iris/dmc/station/rules/UnitTable.java index ef6500f..907b2a2 100644 --- a/src/main/java/edu/iris/dmc/station/rules/UnitTable.java +++ b/src/main/java/edu/iris/dmc/station/rules/UnitTable.java @@ -8,7 +8,7 @@ public class UnitTable { private UnitTable() { } - + // Blank strings are appendend to make list print correctly in the --units argument public static final List units = new ArrayList(Arrays.asList("meter", "meters", "m", "m/s", "m/s**2", "centimeter", "centimeters", "cm", "cm/s", "cm/s**2", "millimeter", "millimeters", "mm", "mm/s", "mm/s**2", "mm/hour", "micrometer", "micrometers", "um", "um/s", "um/s**2", "nanometer", "nm", "nm/s", "nm/s**2", @@ -20,9 +20,9 @@ private UnitTable() { "ampere", "amperes", "A", "milliamp", "milliamps", "mA", "volt", "volts", "V", "millivolt", "millivolts", "mV", "microvolt", "microvolts", "uV", "ohm", "hertz", "Hz", "newton", "newtons", "N", "joule", "joules", "J", "tesla", "T", "nanotesla", "nT", "strain", "m/m", "m**3/m**3", "cm/cm", "mm/mm", "um/um", "nm/nm", - "microstrain", "watt", "watts", "W", "milliwatt", "milliwatts", "mW", "V/m", "W/m**2", "gap", "reboot", + "microstrain", "watt", "watts", "W", "milliwatt", "milliwatts", "mW", "V/m", "W/m**2","hit/(cm**2*hour)", "gap", "reboot", "byte", "bytes", "bit", "bit/s", "percent", "%", "count", "counts", "number", "unitless", "unknown", - "UNKNOWN")); + "UNKNOWN", "", "")); public static boolean contains(String name) { return units.contains(name); diff --git a/src/test/java/edu/iris/dmc/station/conditions/OrientationConditionTest.java b/src/test/java/edu/iris/dmc/station/conditions/OrientationConditionTest.java index ab1951d..26a5ea6 100644 --- a/src/test/java/edu/iris/dmc/station/conditions/OrientationConditionTest.java +++ b/src/test/java/edu/iris/dmc/station/conditions/OrientationConditionTest.java @@ -45,7 +45,7 @@ public void e() throws Exception { Restriction[] restrictions = new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }; Network iu = theDocument.getNetwork().get(0); Station anmo = iu.getStations().get(0); - OrientationCondition condition = new OrientationCondition(true, "", restrictions); + OrientationConditionE condition = new OrientationConditionE(true, "", restrictions); Channel channel = anmo.getChannels().get(0); Message result = condition.evaluate(channel); assertTrue(result instanceof edu.iris.dmc.station.rules.Warning); @@ -60,7 +60,7 @@ public void z() throws Exception { Restriction[] restrictions = new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }; Network iu = theDocument.getNetwork().get(0); Station anmo = iu.getStations().get(0); - OrientationCondition condition = new OrientationCondition(true, "", restrictions); + OrientationConditionZ condition = new OrientationConditionZ(true, "", restrictions); Channel channel = anmo.getChannels().get(0); Message result = condition.evaluate(channel); assertTrue(result instanceof edu.iris.dmc.station.rules.Warning); diff --git a/src/test/resources/F1_330.xml b/src/test/resources/F1_330.xml index 0662827..2957145 100644 --- a/src/test/resources/F1_330.xml +++ b/src/test/resources/F1_330.xml @@ -26,7 +26,7 @@ 225.879999 0 361 - 0 + 10 CONTINUOUS GEOPHYSICAL 2E01 diff --git a/src/test/resources/P1_413.xml b/src/test/resources/P1_413.xml index 4cf2858..3b54064 100644 --- a/src/test/resources/P1_413.xml +++ b/src/test/resources/P1_413.xml @@ -45,19 +45,24 @@ CI/PAS pressure sensor - - 1 - 1E0 - - PA - Pressure in Pascals - - - COUNTS - Digital Counts - - - + + + PA + PRESSURE in Pascals + + + COUNTS + DIGITAL UNIT in Counts + + MACLAURIN + 0.0 + 0.0 + 90000.0 + 106000 + 0.00000 + 90000.0 + 0.614258 + PA