/**
* JHOVE2 - Next-generation architecture for format-aware characterization
*
* Copyright (c) 2009 by The Regents of the University of California,
* Ithaka Harbors, Inc., and The Board of Trustees of the Leland Stanford
* Junior University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of the University of California/California Digital
* Library, Ithaka Harbors/Portico, or Stanford University, nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jhove2.app.util;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.Math;
/**
*
* @author isaac32767
*/
public class ARules {
private static enum Quantifier {
ANY_OF,
ALL_OF,
NONE_OF
}
private static class Command {
public String commandText;
public int line;
}
private static class Rule {
public String name;
public Quantifier quantifier = null;
public boolean enabled;
public String description = "";
public String consequent = "";
public String alternative = "";
public List<String> predicates = new ArrayList<String>();
}
private static class Ruleset {
public String name;
public boolean enabled;
public String objectFilter;
public String description = "";
public List<Rule> rules = new ArrayList<Rule>();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Pattern rulesetPattern =
Pattern.compile("^ruleset\\s+(\\w+)" +
"\\s+(enabled|disabled)" +
"\\s+([:_A-Za-z][-.:_A-Za-z0-9]*)\\s*$");
Pattern rulePattern =
Pattern.compile("^rule\\s+(\\w+)" +
"\\s+(enabled|disabled)\\s*$");
Pattern etcPattern =
Pattern.compile("^(desc|cons|alt|quant|pred)\\s+(.*\\S)\\s*$");
List<Ruleset> rulesets = new ArrayList<Ruleset>();
for (String arg : args) {
Ruleset currentRuleset = null;
Rule currentRule = null;
Command c;
Matcher m;
try {
reader = new LineNumberReader(new FileReader(arg));
} catch (FileNotFoundException ex) {
System.err.println("Can't open file: " + ex.toString());
System.exit(1);
}
try {
while ((c = getCommand()) != null) {
m = rulesetPattern.matcher(c.commandText);
if (m.matches()) {
if (currentRuleset != null) {
System.err.printf("Second ruleset in %s line %d\n",
arg, c.line);
System.exit(1);
}
rulesets.add(currentRuleset = new Ruleset());
currentRuleset.name = m.group(1);
currentRuleset.enabled = m.group(2).equals("enabled");
currentRuleset.objectFilter = m.group(3);
continue;
}
//If we got here, there better be a currentRuleset object
if (currentRuleset == null) {
System.err.println("Ruleset not first statement in " +
arg);
System.exit(1);
}
m = rulePattern.matcher(c.commandText);
if(m.matches()) {
if (currentRule != null) {
if (incompleteRule(currentRule)) {
System.err.printf("In %s, rule ends without all" +
" values at line %d\n", arg, c.line);
System.exit(1);
}
}
currentRuleset.rules.add(currentRule = new Rule());
currentRule.name = m.group(1);
currentRule.enabled = m.group(2).equals("enabled");
continue;
}
m = etcPattern.matcher(c.commandText);
if (m.matches()) {
if (currentRule == null && !m.group(1).equals("desc")) {
System.err.printf("Missing rule statement in %s at " +
"line %d\n", arg, c.line);
System.exit(1);
}
if (m.group(1).equals("desc")) {
if (currentRule == null) {
currentRuleset.description = m.group(2);
} else {
currentRule.description = m.group(2);
}
} else if (m.group(1).equals("cons")) {
currentRule.consequent = m.group(2);
} else if (m.group(1).equals("alt")) {
currentRule.alternative = m.group(2);
} else if (m.group(1).equals("quant")) {
if (m.group(2).equals("all")) {
currentRule.quantifier = Quantifier.ALL_OF;
} else if (m.group(2).equals("any")) {
currentRule.quantifier = Quantifier.ANY_OF;
} else {
currentRule.quantifier = Quantifier.NONE_OF;
}
} else { //pred
currentRule.predicates.add(m.group(2));
}
continue;
}
//Statement didn't match any patterns!
System.err.printf("Invalid statement in %s at line %d\n",
arg, c.line);
}
if (incompleteRule(currentRule)) {
System.err.println("Last rule in " + arg + " is incomplete");
System.exit(1);
}
if (incompleteRuleset(currentRuleset)) {
System.err.println("Ruleset in " + arg + " is incomplete");
}
} catch (IOException ex) {
System.err.println("IO Error: " + ex.toString());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
System.err.println("IO Error: " + ex.toString());
}
}
}
} //for args
String[] xmlPrefix = {
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<beans xmlns=\"http://www.springframework.org/schema/beans\"",
" xmlns:util=\"http://www.springframework.org/schema/util\"",
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
" xmlns:context=\"http://www.springframework.org/schema/context\"",
" xsi:schemaLocation=\"http://www.springframework.org/schema/beans ",
" http://www.springframework.org/schema/beans/spring-beans-2.5.xsd",
" http://www.springframework.org/schema/context",
" http://www.springframework.org/schema/context/spring-context-2.5.xsd",
" http://www.springframework.org/schema/util",
" http://www.springframework.org/schema/util/spring-util-2.0.xsd\">",
""
};
for (String s : xmlPrefix) {
System.out.println(s);
}
for (Ruleset rs: rulesets) {
System.out.printf(
" <bean id=\"%s\"" +
" class=\"org.jhove2.module.assess.RuleSet\"" +
" scope=\"singleton\">\n", rs.name);
System.out.printf(
" <property name=\"name\" value=\"%s\"/>\n",
rs.name);
System.out.printf(
" <property name=\"description\" value=\"%s\"/>\n",
rs.description);
System.out.printf(
" <property name=\"objectFilter\" value=\"%s\"/>\n",
rs.objectFilter);
System.out.println(
" <property name=\"rules\">");
System.out.println(
" <list" +
" value-type=\"org.jhove2.module.assess.Rule\">");
for (Rule r: rs.rules) {
System.out.printf(
" <ref local=\"%s\"/>\n", r.name);
}
System.out.println(
" </list>");
System.out.println(
" </property>");
System.out.printf(
" <property name=\"enabled\" value=\"%b\"/>\n",
rs.enabled);
System.out.println(
" </bean>");
for (Rule r: rs.rules) {
System.out.printf(
" <bean id=\"%s\"" +
" class=\"org.jhove2.module.assess.Rule\"" +
" scope=\"singleton\">\n",
r.name);
System.out.printf(
" <property name=\"name\" value=\"%s\"/>\n",
r.name);
System.out.printf(
" <property name=\"description\" value=\"%s\"/>\n",
r.description);
System.out.printf(
" <property name=\"consequent\" value=\"%s\"/>\n",
r.consequent);
System.out.printf(
" <property name=\"alternative\" value=\"%s\"/>\n",
r.alternative);
System.out.printf(
" <property name=\"quantifier\" value=\"%s\"/>\n",
r.quantifier.name());
System.out.println(
" <property name=\"predicates\">");
System.out.println(
" <list value-type=\"java.lang.String\">");
for (String s: r.predicates) {
System.out.printf(
" <value><![CDATA[%s]]></value>\n",
s);
}
System.out.println(
" </list></property>");
System.out.printf(
" <property name=\"enabled\" value=\"%b\"/>\n",
r.enabled);
System.out.println(
" </bean>");
} //Rules
} //Rulesets
System.out.println("</beans>");
}
private static LineNumberReader reader;
private static boolean incompleteRuleset(Ruleset r) {
return r.description.isEmpty() || r.rules.isEmpty();
}
private static boolean incompleteRule(Rule r) {
return r.description.isEmpty() || r.consequent.isEmpty() ||
r.alternative.isEmpty() || r.predicates.isEmpty() ||
r.quantifier == null;
}
private static Command getCommand() throws IOException {
Command c = new Command();
String continued;
do {
if ((c.commandText = reader.readLine()) == null) {
return null;
}
//Trim right only in case first command is indented
c.commandText = rightTrim(c.commandText);
} while (c.commandText.isEmpty()); // Only empty before first command
c.line = reader.getLineNumber();
reader.mark(1000);
//Suck up everything up to but not including next command or EOF
while ((continued = reader.readLine()) != null &&
(continued.isEmpty() ||
continued.charAt(0) == ' ' ||
continued.charAt(0) == '\t')) {
c.commandText += " " + continued.trim();
reader.mark(1000);
}
//Roll back following statement (if any)
if (continued != null) {
reader.reset();
}
return c;
}
private static String rightTrim(String s) {
return ("x" + s).trim().substring(1);
}
//ARules is a utility class, so please don't instantiate it.
private ARules() {
throw new AssertionError();
}
}