summaryrefslogtreecommitdiffstats
path: root/javatoscachecker/kwalify/src
diff options
context:
space:
mode:
Diffstat (limited to 'javatoscachecker/kwalify/src')
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/BaseException.java51
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/CommandOptionException.java33
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Defaultable.java18
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/DefaultableHashMap.java48
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/InvalidPathException.java23
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/InvalidTypeException.java21
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/KwalifyException.java20
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java19
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Main.java305
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Messages.java51
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/MetaValidator.java475
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Parser.java19
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/PlainYamlParser.java870
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Rule.java673
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/SchemaException.java22
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/SyntaxException.java28
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Types.java107
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Util.java646
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/ValidationException.java26
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/Validator.java415
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/YamlParser.java156
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/YamlSyntaxException.java23
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/YamlUtil.java62
-rw-r--r--javatoscachecker/kwalify/src/main/java/kwalify/messages.properties110
-rw-r--r--javatoscachecker/kwalify/src/main/resources/kwalify/messages.properties110
25 files changed, 4331 insertions, 0 deletions
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/BaseException.java b/javatoscachecker/kwalify/src/main/java/kwalify/BaseException.java
new file mode 100644
index 0000000..c2cc83b
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/BaseException.java
@@ -0,0 +1,51 @@
+/*
+ * @(#)BaseException.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * base class of ValidationException and SchemaException.
+ *
+ * @revision $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ */
+public abstract class BaseException extends KwalifyRuntimeException implements Comparable {
+
+ String _ypath;
+ Object _value;
+ Rule _rule;
+ String _errorSymbol;
+ int _linenum = -1;
+
+ public BaseException(String message, String ypath, Object value, Rule rule, String errorSymbol) {
+ super(message);
+ _ypath = ypath;
+ _value = value;
+ _rule = rule;
+ _errorSymbol = errorSymbol;
+ }
+
+ public String getPath() { return _ypath.equals("") ? "/" : _ypath; }
+ //public void setPath(String ypath) { _ypath = ypath; }
+
+ public Object getValue() { return _value; }
+ //public void setValue(Object value) { _value = value; }
+
+ public Rule getRule() { return _rule; }
+ //
+ //public void setRule(Rule rule) { _rule = rule; }
+
+ public String getErrorSymbol() { return _errorSymbol; }
+ //public void setErrorSymbol(String errorSymbol) { _errorSymbol = errorSymbol; }
+
+ public int getLineNumber() { return _linenum; }
+ public void setLineNumber(int linenum) { _linenum = linenum; }
+
+ public int compareTo(Object obj) {
+ int n = ((ValidationException)obj).getLineNumber();
+ return _linenum - n;
+ }
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/CommandOptionException.java b/javatoscachecker/kwalify/src/main/java/kwalify/CommandOptionException.java
new file mode 100644
index 0000000..e35be85
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/CommandOptionException.java
@@ -0,0 +1,33 @@
+/*
+ * @(#)CommandOptionException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown if command-line option is wrong
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class CommandOptionException extends KwalifyException {
+ private static final long serialVersionUID = 6433387612335104714L;
+
+ private String _error_symbol = null;
+ private char _option;
+
+ public CommandOptionException(String message, char option, String error_symbol) {
+ super(message);
+ _option = option;
+ _error_symbol = error_symbol;
+ }
+
+ public String getErrorSymbol() { return _error_symbol; }
+ public void setErrorSymbol(String error_symbol) { _error_symbol = error_symbol; }
+
+ public char getOption() { return _option; }
+ public void setOption(char option) { _option = option; }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Defaultable.java b/javatoscachecker/kwalify/src/main/java/kwalify/Defaultable.java
new file mode 100644
index 0000000..7e7c692
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Defaultable.java
@@ -0,0 +1,18 @@
+/*
+ * @(#)Defaultable.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * interface to have default value
+ *
+ * @revision $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ */
+public interface Defaultable {
+ public Object getDefault();
+ public void setDefault(Object value);
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/DefaultableHashMap.java b/javatoscachecker/kwalify/src/main/java/kwalify/DefaultableHashMap.java
new file mode 100644
index 0000000..0009205
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/DefaultableHashMap.java
@@ -0,0 +1,48 @@
+/*
+ * @(#)DefaultableHashMap.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * hash map which can have default value
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class DefaultableHashMap extends HashMap implements Defaultable {
+
+ private static final long serialVersionUID = -5224819562023897380L;
+
+ private Object _default = null;
+
+ public DefaultableHashMap() {
+ super();
+ }
+
+ public DefaultableHashMap(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ public DefaultableHashMap(int initialCapacity, float loadFactor) {
+ super(initialCapacity, loadFactor);
+ }
+
+ public DefaultableHashMap(Map m) {
+ super(m);
+ }
+
+ public Object getDefault() { return _default; }
+
+ public void setDefault(Object value) { _default = value; }
+
+ public Object get(Object key) {
+ return containsKey(key) ? super.get(key) : _default;
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/InvalidPathException.java b/javatoscachecker/kwalify/src/main/java/kwalify/InvalidPathException.java
new file mode 100644
index 0000000..94eeca2
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/InvalidPathException.java
@@ -0,0 +1,23 @@
+/*
+ * @(#)InvalidPathException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown by YamlParser#setErrorsLineNumber() when path is wrong
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class InvalidPathException extends KwalifyRuntimeException {
+ private static final long serialVersionUID = -4601461998104850880L;
+
+ //private int _linenum;
+
+ public InvalidPathException(String message) {
+ super(message);
+ }
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/InvalidTypeException.java b/javatoscachecker/kwalify/src/main/java/kwalify/InvalidTypeException.java
new file mode 100644
index 0000000..fe60ca0
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/InvalidTypeException.java
@@ -0,0 +1,21 @@
+/*
+ * @(#)InvalidTypeException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown by Util.compareValues() when comparing different type values.
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class InvalidTypeException extends KwalifyRuntimeException {
+ private static final long serialVersionUID = -6937887618526171845L;
+
+ public InvalidTypeException(String message) {
+ super(message);
+ }
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/KwalifyException.java b/javatoscachecker/kwalify/src/main/java/kwalify/KwalifyException.java
new file mode 100644
index 0000000..976a263
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/KwalifyException.java
@@ -0,0 +1,20 @@
+/*
+ * @(#)KwalifyException.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * base exception class of all exception in Kwalify
+ *
+ * @revision $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ * @see KwalifyRuntimeException
+ */
+public abstract class KwalifyException extends Exception {
+ public KwalifyException(String message) {
+ super(message);
+ }
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java b/javatoscachecker/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java
new file mode 100644
index 0000000..75e4764
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java
@@ -0,0 +1,19 @@
+/*
+ * @(#)KwalifyRuntimeException.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * base class of all runtime exception class in Kwalify
+ *
+ * @revision $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ */
+public abstract class KwalifyRuntimeException extends RuntimeException {
+ public KwalifyRuntimeException(String message) {
+ super(message);
+ }
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Main.java b/javatoscachecker/kwalify/src/main/java/kwalify/Main.java
new file mode 100644
index 0000000..d2c39e2
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Main.java
@@ -0,0 +1,305 @@
+/*
+ * @(#)Main.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Collections;
+import java.util.regex.Matcher;
+import java.io.IOException;
+
+/**
+ * class for main program
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class Main {
+
+ private String _command;
+ private boolean _flag_help = false; // print help
+ private boolean _flag_version = false; // print version
+ private boolean _flag_silent = false; // suppress messages
+ private boolean _flag_meta = false; // meta validation
+ private boolean _flag_untabify = false; // expand tab charactor to spaces
+ private boolean _flag_emacs = false; // show errors in emacs style
+ private boolean _flag_linenum = false; // show line number on where errors happened
+ private boolean _flag_debug = false; // internal use only
+ private String _schema_filename = null; // schema filename
+ private Map _properties = new HashMap();
+
+
+ boolean isDebug() { return _flag_debug; }
+
+
+ public String inspect() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("command : ").append(_command ).append('\n');
+ sb.append("flag_help : ").append(_flag_help ).append('\n');
+ sb.append("flag_version : ").append(_flag_version ).append('\n');
+ sb.append("flag_silent : ").append(_flag_silent ).append('\n');
+ sb.append("flag_meta : ").append(_flag_meta ).append('\n');
+ sb.append("flag_untabify : ").append(_flag_untabify ).append('\n');
+ sb.append("flag_emacs : ").append(_flag_emacs ).append('\n');
+ sb.append("flag_linenum : ").append(_flag_linenum ).append('\n');
+ sb.append("flag_debug : ").append(_flag_debug ).append('\n');
+ sb.append("schema_filename : ").append(_schema_filename).append('\n');
+ sb.append("properties:\n");
+ for (Iterator it = _properties.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object val = _properties.get(key);
+ sb.append(" ").append(key).append(": ").append(val).append('\n');
+ }
+ return sb.toString();
+ }
+
+
+ private static final String REVISION = "$Release: 0.5.1 $";
+ private static final String HELP = ""
+ + "Usage1: %s [-hvstlE] -f schema.yaml doc.yaml [doc2.yaml ...]\n"
+ + "Usage2: %s [-hvstlE] -m schema.yaml [schema2.yaml ...]\n"
+ + " -h, --help : help\n"
+ + " -v : version\n"
+ + " -s : silent\n"
+ + " -f schema.yaml : schema definition file\n"
+ + " -m : meta-validation mode\n"
+ + " -t : expand tab character automatically\n"
+ + " -l : show linenumber when errored (experimental)\n"
+ + " -E : show errors in emacs-style (implies '-l')\n"
+ ;
+
+
+ public Main(String command) {
+ _command = command;
+ }
+
+
+ public String execute(String[] args) throws IOException, CommandOptionException, SyntaxException {
+ // parse command-line options
+ String[] filenames = parseOptions(args);
+
+ // help or version
+ StringBuffer sb = new StringBuffer();
+ if (_flag_version) {
+ sb.append(version()).append('\n');
+ }
+ if (_flag_help) {
+ sb.append(help());
+ }
+ if (sb.length() > 0) {
+ return sb.toString();
+ }
+
+ // main
+ String s = null;
+ if (_flag_meta) {
+ s = metaValidate(filenames);
+ } else if (_schema_filename == null) {
+ throw optionError("command.option.noaction", '\0');
+ } else if (_flag_debug) {
+ s = inspectSchemaFile(_schema_filename);
+ } else {
+ s = validate(filenames, _schema_filename);
+ }
+
+ //
+ return s;
+ }
+
+
+ private String[] parseOptions(String[] args) throws CommandOptionException {
+ Object[] ret = null;
+ try {
+ ret = Util.parseCommandOptions(args, "hvsmtlED", "f", null);
+ } catch (CommandOptionException ex) {
+ String error_symbol = ex.getErrorSymbol();
+ if (error_symbol.equals("command.option.noarg")) {
+ switch (ex.getOption()) {
+ case 'f': error_symbol = "command.option.noschema"; break;
+ default:
+ assert false;
+ }
+ }
+ throw optionError(error_symbol, ex.getOption());
+ }
+ //
+ Map options = (Map)ret[0];
+ Map properties = (Map)ret[1];
+ String[] filenames = (String[])ret[2];
+ //
+ _flag_help = options.get("h") != null;
+ _flag_version = options.get("v") != null;
+ _flag_silent = options.get("s") != null;
+ _flag_meta = options.get("m") != null;
+ _flag_untabify = options.get("t") != null;
+ _flag_emacs = options.get("E") != null;
+ _flag_linenum = options.get("l") != null || _flag_emacs;
+ _flag_debug = options.get("D") != null;
+ _schema_filename = (String)options.get("f");
+ //
+ //
+ _properties = properties;
+ if (_properties.get("help") != null) {
+ _flag_help = true;
+ }
+ //
+ return filenames;
+ }
+
+
+ private String validate(String[] filenames, String schema_filename) throws IOException, SyntaxException {
+ String str = Util.readFile(schema_filename);
+ if (_flag_untabify) {
+ str = Util.untabify(str);
+ }
+ YamlParser parser = new YamlParser(str);
+ Object schema = parser.parse();
+ Validator validator = new Validator(schema);
+ String s = validateFiles(validator, filenames);
+ return s;
+ }
+
+
+ private String validateFiles(Validator validator, String[] filenames) throws IOException, SyntaxException {
+ if (filenames.length == 0) {
+ filenames = new String[] { null };
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int j = 0; j < filenames.length; j++) {
+ String filename = filenames[j];
+ String str = null;
+ if (filename == null) {
+ str = Util.readInputStream(System.in);
+ filename = "(stdin)";
+ } else {
+ str = Util.readFile(filename);
+ }
+ if (_flag_untabify) {
+ str = Util.untabify(str);
+ }
+ YamlParser parser = new YamlParser(str);
+ int i = 0;
+ while (parser.hasNext()) {
+ Object doc = parser.parse();
+ validateDocument(sb, validator, doc, filename, i, parser);
+ i++;
+ }
+ }
+ return sb.toString();
+ }
+
+
+ private void validateDocument(StringBuffer sb, Validator validator, Object doc, String filename, int i, YamlParser parser) {
+ if (doc == null) {
+ Object[] args = { filename, new Integer(i) };
+ String msg = Messages.buildMessage("validation.empty", null, args);
+ sb.append(msg).append('\n');
+ return;
+ }
+ List errors = validator.validate(doc);
+ Object[] args = { filename, new Integer(i) };
+ if (errors == null || errors.size() == 0) {
+ if (! _flag_silent) {
+ String msg = Messages.buildMessage("validation.valid", args);
+ sb.append(msg).append('\n');
+ }
+ } else {
+ String msg = Messages.buildMessage("validation.invalid", args);
+ sb.append(msg).append('\n');
+ if (_flag_linenum) {
+ assert parser != null;
+ parser.setErrorsLineNumber(errors);
+ Collections.sort(errors);
+ }
+ for (Iterator it = errors.iterator(); it.hasNext(); ) {
+ ValidationException error = (ValidationException)it.next();
+ if (_flag_emacs) {
+ assert _flag_linenum;
+ sb.append(filename).append(":").append(error.getLineNumber()).append(":");
+ } else if (_flag_linenum) {
+ sb.append(" - (line ").append(error.getLineNumber()).append(")");
+ } else {
+ sb.append(" -");
+ }
+ sb.append(" [").append(error.getPath()).append("] ").append(error.getMessage()).append('\n');
+ }
+ }
+ }
+
+
+ private String metaValidate(String[] filenames) throws IOException, SyntaxException {
+ Validator meta_validator = MetaValidator.instance();
+ String s = validateFiles(meta_validator, filenames);
+ return s;
+ }
+
+
+ private String inspectSchemaFile(String schema_filename) throws IOException, SyntaxException {
+ String filename = schema_filename;
+ String content = filename != null ? Util.readFile(filename) : Util.readInputStream(System.in);
+ YamlParser parser = new YamlParser(content);
+ Object schema = parser.parse();
+ if (schema == null) {
+ return null;
+ }
+ Validator validator = new Validator(schema); // SchemaException is thrown when schema is wrong
+ String s = validator.getRule().inspect();
+ if (s.charAt(s.length() - 1) != '\n') {
+ s = s + '\n';
+ }
+ return s;
+ }
+
+
+ private static CommandOptionException optionError(String error_symbol, char option) {
+ Object[] args = { Character.toString(option) };
+ String message = Messages.buildMessage(error_symbol, null, args);
+ return new CommandOptionException(message, option, error_symbol);
+ }
+
+
+ private String version() {
+ Matcher m = Util.matcher(REVISION, "[.\\d]+");
+ m.find();
+ String version = m.group(0);
+ return version;
+ }
+
+
+ private String help() {
+ String help_msg = Messages.buildMessage("command.help", null, new Object[] { _command, _command });
+ //String help = HELP.replaceAll("%s", _command);
+ return help_msg;
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ int status = 0;
+ Main main = null;
+ try {
+ main = new Main("kwalify-java");
+ String result = main.execute(args);
+ if (result != null) {
+ System.out.println(result);
+ }
+ } catch (Exception ex) {
+ if (main != null && main.isDebug()) {
+ throw ex;
+ }
+ if ( ex instanceof CommandOptionException
+ || ex instanceof SyntaxException
+ || ex instanceof IOException) {
+ System.err.println("ERROR: " + ex.getMessage());
+ status = 1;
+ }
+ }
+ System.exit(status);
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Messages.java b/javatoscachecker/kwalify/src/main/java/kwalify/Messages.java
new file mode 100644
index 0000000..b77f04b
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Messages.java
@@ -0,0 +1,51 @@
+/*
+ * @(#)Messages.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.ResourceBundle;
+//import java.util.Locale;
+
+/**
+ * set of utility methods around messages.
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class Messages {
+
+ private static final String __basename = "kwalify.messages";
+ private static ResourceBundle __messages = ResourceBundle.getBundle(__basename);
+ //private static ResourceBundle __messages = ResourceBundle.getBundle(__basename, Locale.getDefault());
+
+ public static String message(String key) {
+ return __messages.getString(key);
+ }
+
+ public static String buildMessage(String key, Object[] args) {
+ return buildMessage(key, null, args);
+ }
+
+ public static String buildMessage(String key, Object value, Object[] args) {
+ String msg = message(key);
+ assert msg != null;
+ if (args != null) {
+ for (int i = 0; i < args.length; i++) { // don't use MessageFormat
+ msg = msg.replaceFirst("%[sd]", escape(args[i]));
+ }
+ }
+ if (value != null && !Types.isCollection(value)) {
+ msg = "'" + escape(value) + "': " + msg;
+ }
+ return msg;
+ }
+
+ private static String escape(Object obj) {
+ //return obj.toString().replaceAll("\\", "\\\\").replace("\n", "\\n"); // J2SK1.4 doesn't support String#replace(CharSequence, CharSequence)!
+ return obj.toString().replaceAll("\\\\", "\\\\\\\\").replaceAll("\\n", "\\\\n");
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/MetaValidator.java b/javatoscachecker/kwalify/src/main/java/kwalify/MetaValidator.java
new file mode 100644
index 0000000..9ce05bd
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/MetaValidator.java
@@ -0,0 +1,475 @@
+/*
+ * @(#)MetaValidator.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * meta validator to validate schema definition
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class MetaValidator extends Validator {
+
+ public static final String META_SCHEMA = ""
+ + "name: MAIN\n"
+ + "type: map\n"
+ + "required: yes\n"
+ + "mapping: &main-rule\n"
+ + " \"name\":\n"
+ + " type: str\n"
+ + " \"desc\":\n"
+ + " type: str\n"
+ + " \"type\":\n"
+ + " type: str\n"
+ + " #required: yes\n"
+ + " enum:\n"
+ + " - seq\n"
+ + " #- sequence\n"
+ + " #- list\n"
+ + " - map\n"
+ + " #- mapping\n"
+ + " #- hash\n"
+ + " - str\n"
+ + " #- string\n"
+ + " - int\n"
+ + " #- integer\n"
+ + " - float\n"
+ + " - number\n"
+ + " #- numeric\n"
+ + " - bool\n"
+ + " #- boolean\n"
+ + " - text\n"
+ + " - date\n"
+ + " - time\n"
+ + " - timestamp\n"
+ + " #- object\n"
+ + " - any\n"
+ + " - scalar\n"
+ + " #- collection\n"
+ + " \"required\":\n"
+ + " type: bool\n"
+ + " \"enum\":\n"
+ + " type: seq\n"
+ + " sequence:\n"
+ + " - type: scalar\n"
+ + " unique: yes\n"
+ + " \"pattern\":\n"
+ + " type: str\n"
+ + " \"assert\":\n"
+ + " type: str\n"
+ + " pattern: /\\bval\\b/\n"
+ + " \"range\":\n"
+ + " type: map\n"
+ + " mapping:\n"
+ + " \"max\":\n"
+ + " type: scalar\n"
+ + " \"min\":\n"
+ + " type: scalar\n"
+ + " \"max-ex\":\n"
+ + " type: scalar\n"
+ + " \"min-ex\":\n"
+ + " type: scalar\n"
+ + " \"length\":\n"
+ + " type: map\n"
+ + " mapping:\n"
+ + " \"max\":\n"
+ + " type: int\n"
+ + " \"min\":\n"
+ + " type: int\n"
+ + " \"max-ex\":\n"
+ + " type: int\n"
+ + " \"min-ex\":\n"
+ + " type: int\n"
+ + " \"ident\":\n"
+ + " type: bool\n"
+ + " \"unique\":\n"
+ + " type: bool\n"
+ + " \"sequence\":\n"
+ + " name: SEQUENCE\n"
+ + " type: seq\n"
+ + " sequence:\n"
+ + " - type: map\n"
+ + " mapping: *main-rule\n"
+ + " name: MAIN\n"
+ + " #required: yes\n"
+ + " \"mapping\":\n"
+ + " name: MAPPING\n"
+ + " type: map\n"
+ + " mapping:\n"
+ + " =:\n"
+ + " type: map\n"
+ + " mapping: *main-rule\n"
+ + " name: MAIN\n"
+ + " #required: yes\n"
+ ;
+
+
+ /**
+ *
+ * ex.
+ * <pre>
+ * MetaValidator meta_validator = MetaValidator();
+ * Map schema = YamlUtil.loadFile("schema.yaml");
+ * List errors = meta_validator.validate(schema);
+ * if (errors != null && errors.size() > 0) {
+ * for (Iterator it = errors.iterator(); it.hasNext(); ) {
+ * ValidationException error = (ValidationException)it.next();
+ * System.err.println(" - [" + error.getPath() + "] " + error.getMessage());
+ * }
+ * }
+ * </pre>
+ */
+
+ private static Validator __instance;
+
+ public static Validator instance() {
+ // should not use double checked pattern?
+ // but it would work well because __instance is read-only.
+ if (__instance == null) {
+ synchronized (MetaValidator.class) {
+ if (__instance == null) {
+ try {
+ Map schema = (Map)YamlUtil.load(META_SCHEMA);
+ __instance = new MetaValidator(schema);
+ } catch (SyntaxException ex) {
+ assert false;
+ }
+ }
+ }
+ }
+ return __instance;
+ }
+
+ private MetaValidator(Map schema) {
+ super(schema);
+ }
+
+ public void postValidationHook(Object value, Rule rule, ValidationContext theContext) {
+ if (value == null) {
+ return; // realy?
+ }
+ if (! "MAIN".equals(rule.getName())) {
+ return;
+ }
+ //
+ assert value instanceof Map;
+ Map map = (Map)value;
+ String type = (String)map.get("type");
+ if (type == null) {
+ type = Types.getDefaultType();
+ }
+ //Class type_class = Types.typeClass(type);
+ //if (type_class == null) {
+ // theContext.addError(validationError("type.unknown", rule, path + "/type", type, null));
+ //}
+ //
+ //String pattern;
+ //if ((pattern = (String)map.get("pattern")) != null) {
+ if (map.containsKey("pattern")) {
+ String pattern = (String)map.get("pattern");
+ Matcher m = Util.matcher(pattern, "\\A\\/(.*)\\/([mi]?[mi]?)\\z");
+ String pat = m.find() ? m.group(1) : pattern;
+ try {
+ Pattern.compile(pat);
+ } catch (PatternSyntaxException ex) {
+ theContext.addError("pattern.syntaxerr", rule, "pattern", pattern, null);
+ }
+ }
+ //
+ //List enum_list;
+ //if ((enum_list = (List)map.get("enum")) != null) {
+ if (map.containsKey("enum")) {
+ List enum_list = (List)map.get("enum");
+ if (Types.isCollectionType(type)) {
+ theContext.addError("enum.notscalar", rule, "enum:", (Object[])null);
+ } else {
+ for (Iterator it = enum_list.iterator(); it.hasNext(); ) {
+ Object elem = it.next();
+ if (! Types.isCorrectType(elem, type)) {
+ theContext.addError("enum.type.unmatch", rule, "enum", elem, new Object[] { Types.typeName(type) });
+ }
+ }
+ }
+ }
+ //
+ //String assert_str;
+ //if ((assert_str = (String)map.get("assert")) != null) {
+ if (map.containsKey("assert")) {
+ System.err.println("*** warning: sorry, 'assert:' is not supported in current version of Kwalify-java.");
+ //String assert_str = (String)map.get("assert");
+ //if (! Util.matches(assert_str, "\\bval\\b")) {
+ // theContext.addError(validationError("assert.noval", rule, path + "/assert", assert_str, null);
+ //}
+ //try {
+ // Expression.parse(assert_str);
+ //} catch (InvalidExpressionException ex) {
+ // theContext.addError(validationError("assert.syntaxerr", rule, path + "/assert", assert_str, null));
+ //}
+ }
+ //
+ //Map range;
+ //if ((range = (Map)map.get("range")) != null) {
+ if (map.containsKey("range")) {
+ Map range = (Map)map.get("range");
+ //if (! (range instanceof Map)) {
+ // theContext.addError(validtionError("range.notmap", rule, path + "/range", range, null));
+ //} else
+ if (Types.isCollectionType(type) || type.equals("bool") || type.equals("any")) {
+ theContext.addError("range.notscalar", rule, "range:", null, null);
+ } else {
+ for (Iterator it = range.keySet().iterator(); it.hasNext(); ) {
+ String k = (String)it.next();
+ Object v = range.get(k);
+ if (! Types.isCorrectType(v, type)) {
+ theContext.addError("range.type.unmatch", rule, "range/" + k, v, new Object[] { Types.typeName(type) });
+ }
+ }
+ }
+ if (range.containsKey("max") && range.containsKey("max-ex")) {
+ theContext.addError("range.twomax", rule, "range", null, null);
+ }
+ if (range.containsKey("min") && range.containsKey("min-ex")) {
+ theContext.addError("range.twomin", rule, "range", null, null);
+ }
+ Object max = range.get("max");
+ Object min = range.get("min");
+ Object max_ex = range.get("max-ex");
+ Object min_ex = range.get("min-ex");
+ Object[] args = null;
+ //String error_symbol = null;
+ if (max != null) {
+ if (min != null && Util.compareValues(max, min) < 0) {
+ args = new Object[] { max, min };
+ theContext.addError("range.maxltmin", rule, "range", null, args);
+ } else if (min_ex != null && Util.compareValues(max, min_ex) <= 0) {
+ args = new Object[] { max, min_ex };
+ theContext.addError("range.maxleminex", rule, "range", null, args);
+ }
+ } else if (max_ex != null) {
+ if (min != null && Util.compareValues(max_ex, min) <= 0) {
+ args = new Object[] { max_ex, min };
+ theContext.addError("range.maxexlemin", rule, "range", null, args);
+ } else if (min_ex != null && Util.compareValues(max_ex, min_ex) <= 0) {
+ args = new Object[] { max_ex, min_ex };
+ theContext.addError("range.maxexleminex", rule, "range", null, args);
+ }
+ }
+ }
+ //
+ //Map length;
+ //if ((length = (Map)map.get("length")) != null) {
+ if (map.containsKey("length")) {
+ Map length = (Map)map.get("length");
+ //if (! (length instanceof Map)) {
+ // theContext.addError(validtionError("length.notmap", rule, path + "/length", length, null));
+ //} else
+ if (! (type.equals("str") || type.equals("text"))) {
+ theContext.addError("length.nottext", rule, "length:", (Object[])null);
+ }
+ //for (Iterator it = length.keySet().iterator(); it.hasNext(); ) {
+ // String k = (String)it.next();
+ // Object v = length.get(k);
+ // if (k == null || ! (k.equals("max") || k.equals("min") || k.equals("max-ex") || k.equals("min-ex"))) {
+ // theContext.addError(validationError("length.undefined", rule, path + "/length/" + k, "" + k + ":", null));
+ // } else if (! (v instanceof Integer)) {
+ // theContext.addError(validationError("length.notint", rule, path + "/length/" + k, v, null));
+ // }
+ //}
+ if (length.containsKey("max") && length.containsKey("max-ex")) {
+ theContext.addError("length.twomax", rule, "length", (Object[])null);
+ }
+ if (length.containsKey("min") && length.containsKey("min-ex")) {
+ theContext.addError("length.twomin", rule, "length", (Object[])null);
+ }
+ Integer max = (Integer)length.get("max");
+ Integer min = (Integer)length.get("min");
+ Integer max_ex = (Integer)length.get("max-ex");
+ Integer min_ex = (Integer)length.get("min-ex");
+ Object[] args = null;
+ //String error_symbol = null;
+ if (max != null) {
+ if (min != null && max.compareTo(min) < 0) {
+ args = new Object[] { max, min };
+ theContext.addError("length.maxltmin", rule, "length", null, args);
+ } else if (min_ex != null && max.compareTo(min_ex) <= 0) {
+ args = new Object[] { max, min_ex };
+ theContext.addError("length.maxleminex", rule, "length", null, args);
+ }
+ } else if (max_ex != null) {
+ if (min != null && max_ex.compareTo(min) <= 0) {
+ args = new Object[] { max_ex, min };
+ theContext.addError("length.maxexlemin", rule, "length", null, args);
+ } else if (min_ex != null && max_ex.compareTo(min_ex) <= 0) {
+ args = new Object[] { max_ex, min_ex };
+ theContext.addError("length.maxexleminex", rule, "length", null, args);
+ }
+ }
+ }
+ //
+ //Boolean unique;
+ //if ((unique = (Boolean)map.get("unique")) != null) {
+ if (map.containsKey("unique")) {
+ Boolean unique = (Boolean)map.get("unique");
+ if (unique.booleanValue() == true && Types.isCollectionType(type)) {
+ theContext.addError("unique.notscalar", rule, "unique:", (Object[])null);
+ }
+ if (theContext.getPath().length() == 0) {
+ theContext.addError("unique.onroot", rule, "", "unique:", null);
+ }
+ }
+ //
+ //Boolean ident;
+ //if ((ident = (Boolean)map.get("ident")) != null) {
+ if (map.containsKey("ident")) {
+ Boolean ident = (Boolean)map.get("ident");
+ if (ident.booleanValue() == true && Types.isCollectionType(type)) {
+ theContext.addError("ident.notscalar", rule, "ident:", (Object[])null);
+ }
+ if (theContext.getPath().length() == 0) {
+ theContext.addError("ident.onroot", rule, "/", "ident:", (Object[])null);
+ }
+ }
+ //
+ //List seq;
+ //if ((seq = (List)map.get("sequence")) != null) {
+ if (map.containsKey("sequence")) {
+ List seq = (List)map.get("sequence");
+ //if (! (seq instanceof List)) {
+ // theContext.addError(validationError("sequence.notseq", rule, path + "/sequence", seq, null));
+ //} else
+ if (seq == null || seq.size() == 0) {
+ theContext.addError("sequence.noelem", rule, "sequence", seq, null);
+ } else if (seq.size() > 1) {
+ theContext.addError("sequence.toomany", rule, "sequence", seq, null);
+ } else {
+ Object item = seq.get(0);
+ assert item instanceof Map;
+ Map m = (Map)item;
+ Boolean ident2 = (Boolean)m.get("ident");
+ if (ident2 != null && ident2.booleanValue() == true && ! "map".equals(m.get("type"))) {
+ theContext.addError("ident.notmap", null, "sequence/0", "ident:", null);
+ }
+ }
+ }
+ //
+ //Map mapping;
+ //if ((mapping = (Map)map.get("mapping")) != null) {
+ if (map.containsKey("mapping")) {
+ Map mapping = (Map)map.get("mapping");
+ //if (mapping != null && ! (mapping instanceof Map)) {
+ // theContext.addError(validationError("mapping.notmap", rule, path + "/mapping", mapping, null));
+ //} else
+ Object default_value = null;
+ if (mapping != null && mapping instanceof Defaultable) {
+ default_value = ((Defaultable)mapping).getDefault();
+ }
+ if (mapping == null || (mapping.size() == 0 && default_value == null)) {
+ theContext.addError("mapping.noelem", rule, "mapping", mapping, null);
+ }
+ }
+ //
+ if (type.equals("seq")) {
+ if (! map.containsKey("sequence")) {
+ theContext.addError("seq.nosequence", rule, null, (Object[])null);
+ }
+ //if (map.containsKey("enum")) {
+ // theContext.addError(validationError("seq.conflict", rule, path, "enum:", null));
+ //}
+ if (map.containsKey("pattern")) {
+ theContext.addError("seq.conflict", rule, "pattern:", (Object[])null);
+ }
+ if (map.containsKey("mapping")) {
+ theContext.addError("seq.conflict", rule, "mapping:", (Object[])null);
+ }
+ //if (map.containsKey("range")) {
+ // theContext.addError(validationError("seq.conflict", rule, path, "range:", null));
+ //}
+ //if (map.containsKey("length")) {
+ // theContext.addError(validationError("seq.conflict", rule, path, "length:", null));
+ //}
+ } else if (type.equals("map")) {
+ if (! map.containsKey("mapping")) {
+ theContext.addError("map.nomapping", rule, null, (Object[])null);
+ }
+ //if (map.containsKey("enum")) {
+ // theContext.addError(validationError("map.conflict", rule, path, "enum:", null));
+ //}
+ if (map.containsKey("pattern")) {
+ theContext.addError("map.conflict", rule, "pattern:", (Object[])null);
+ }
+ if (map.containsKey("sequence")) {
+ theContext.addError("map.conflict", rule, "sequence:", (Object[])null);
+ }
+ //if (map.containsKey("range")) {
+ // theContext.addError(validationError("map.conflict", rule, path, "range:", null));
+ //}
+ //if (map.containsKey("length")) {
+ // theContext.addError(validationError("map.conflict", rule, path, "length:", null));
+ //}
+ } else {
+ if (map.containsKey("sequence")) {
+ theContext.addError("scalar.conflict", rule, "sequence:", (Object[])null);
+ }
+ if (map.containsKey("mapping")) {
+ theContext.addError("scalar.conflict", rule, "mapping:", (Object[])null);
+ }
+ if (map.containsKey("enum")) {
+ if (map.containsKey("range")) {
+ theContext.addError("enum.conflict", rule, "range:", (Object[])null);
+ }
+ if (map.containsKey("length")) {
+ theContext.addError("enum.conflict", rule, "length:", (Object[])null);
+ }
+ if (map.containsKey("pattern")) {
+ theContext.addError("enum.conflict", rule, "pattern:", (Object[])null);
+ }
+ }
+ }
+ }
+
+/*
+ public static void main(String[] args) {
+ try {
+ // parse schema
+ String filename = args.length > 0 ? args[0] : "schema.yaml";
+ String schema_str = Util.readFile(filename);
+ YamlParser parser = new YamlParser(schema_str);
+ Object schema = parser.parse();
+
+ // validate schema
+ Validator meta_validator = MetaValidator.instance();
+ List errors = meta_validator.validate(schema);
+
+ // show errors
+ if (errors != null && errors.size() > 0) {
+ parser.setErrorsLineNumber(errors);
+ for (Iterator it = errors.iterator(); it.hasNext(); ) {
+ ValidationException error = (ValidationException)it.next();
+ int linenum = error.getLineNumber();
+ String path = error.getPath();
+ String msg = error.getMessage();
+ System.out.println("- line " + linenum + ": [" + path + "] " + msg);
+ }
+ } else {
+ System.out.println("meta validation: OK.");
+ }
+ } catch (SyntaxException ex) {
+ ex.printStackTrace();
+ } catch (java.io.IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+*/
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Parser.java b/javatoscachecker/kwalify/src/main/java/kwalify/Parser.java
new file mode 100644
index 0000000..53c6272
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Parser.java
@@ -0,0 +1,19 @@
+/*
+ * @(#)Parser.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * interface for any parser
+ *
+ * @revision $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ */
+public interface Parser {
+
+ public Object parse() throws SyntaxException;
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/PlainYamlParser.java b/javatoscachecker/kwalify/src/main/java/kwalify/PlainYamlParser.java
new file mode 100644
index 0000000..6224044
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/PlainYamlParser.java
@@ -0,0 +1,870 @@
+/*
+ * @(#)PlainYamlParser.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * plain yaml parser class which is a parent of YamlParser class.
+ *
+ * ex.
+ * <pre>
+ * String str = kwalify.Util.readFile("document.yaml");
+ * kwalify.Parser parser = new kwalify.PlainYamlParser(str);
+ * Object doc = parser.parse();
+ * </pre>
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class PlainYamlParser implements Parser {
+
+ public static class Alias {
+ private String _label;
+ private int _linenum;
+
+ public Alias(String label, int linenum) {
+ _label = label;
+ _linenum = linenum;
+ }
+
+ public String getLabel() { return _label; }
+ public void setLabel(String label) { _label = label; }
+
+ public int getLineNumber() { return _linenum; }
+ public void setLineNumber(int linenum) { _linenum = linenum; }
+ }
+
+
+ private String[] _lines;
+ private String _line = null;
+ private int _linenum = 0;
+ private Map _anchors = new HashMap();
+ private Map _aliases = new HashMap(); // key: label, value: Integer
+ private Object _end_flag = null;
+ private String _sbuf = null;
+ private int _index = 0;
+
+ public PlainYamlParser(String yaml_str) {
+ // split yaml_str into _lines
+ List list = Util.toListOfLines(yaml_str);
+ int len = list.size();
+ _lines = new String[len + 1];
+ for (int i = 0; i < len; i++) {
+ _lines[i + 1] = (String)list.get(i);
+ }
+ }
+
+ public Object parse() throws SyntaxException {
+ Object data = parseChild(0);
+ if (data == null && _end_flag == ENDFLAG_DOC_BEGIN) {
+ data = parseChild(0);
+ }
+ if (_aliases.size() > 0) {
+ resolveAliases(data);
+ }
+ //System.err.println("*** debug: data = " + Util.inspect(data));
+ //System.err.println("*** debug: data = " + data.toString());
+ return data;
+ }
+
+ public boolean hasNext() {
+ return _end_flag != ENDFLAG_EOF;
+ }
+
+ public Object[] parseAll() throws SyntaxException {
+ List docs = new ArrayList();
+ while (hasNext()) {
+ Object doc = parse();
+ docs.add(doc);
+ }
+ return docs.toArray();
+ }
+
+
+ protected List createSequence(int linenum) {
+ return new ArrayList();
+ }
+
+ //private List createSequence() {
+ // return createSequence(_linenum);
+ //}
+
+ protected void addSequenceValue(List seq, Object value, int linenum) {
+ seq.add(value);
+ }
+
+ protected void setSequenceValueAt(List seq, int index, Object value, int linenum) {
+ seq.set(index, value);
+ }
+
+ protected Map createMapping(int linenum) {
+ return new DefaultableHashMap();
+ }
+
+ //private Map createMapping() {
+ // return createMapping(_linenum);
+ //}
+
+ protected void setMappingValueWith(Map map, Object key, Object value, int linenum) {
+ map.put(key, value);
+ }
+
+ protected void setMappingDefault(Map map, Object value, int linenum) {
+ if (map instanceof Defaultable) {
+ ((Defaultable)map).setDefault(value);
+ }
+ }
+
+ protected void mergeMapping(Map map, Map map2, int linenum) {
+ for (Iterator it = map2.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ if (! map.containsKey(key)) {
+ Object value = map2.get(key);
+ map.put(key, value);
+ }
+ }
+ }
+
+ protected void mergeList(Map map, List maplist, int linenum) throws SyntaxException {
+ for (Iterator it = maplist.iterator(); it.hasNext(); ) {
+ Object elem = it.next();
+ mergeCollection(map, elem, linenum);
+ }
+ }
+
+ protected void mergeCollection(Map map, Object collection, int linenum) throws SyntaxException {
+ if (collection instanceof Map) {
+ mergeMapping(map, (Map)collection, linenum);
+ } else if (collection instanceof List) {
+ mergeList(map, (List)collection, linenum);
+ } else {
+ throw syntaxError("'<<' requires collection (mapping, or sequence of mapping).");
+ }
+ }
+
+ protected Object createScalar(Object value, int linenum) {
+ return value;
+ }
+
+ private Object createScalar(Object value) {
+ return createScalar(value, _linenum);
+ }
+
+ protected String currentLine() {
+ return _line;
+ }
+
+ protected int currentLineNumber() {
+ return _linenum;
+ }
+
+ protected String getLine() {
+ String line;
+ do {
+ line = _getLine_();
+ } while (line != null && Util.matches(line, "^\\s*($|#)"));
+ return line;
+ }
+
+ protected String _getLine_() {
+ if (++_linenum < _lines.length) {
+ _line = _lines[_linenum];
+ if (Util.matches(_line, "^\\.\\.\\.$")) {
+ _line = null;
+ _end_flag = ENDFLAG_DOC_END;
+ } else if (Util.matches(_line, "^---( [!%].*)?$")) {
+ _line = null;
+ _end_flag = ENDFLAG_DOC_BEGIN;
+ }
+ } else {
+ _line = null;
+ _end_flag = ENDFLAG_EOF;
+ }
+ return _line;
+ }
+
+ protected static final String ENDFLAG_EOF = "<EOF>";
+ protected static final String ENDFLAG_DOC_BEGIN = "---";
+ protected static final String ENDFLAG_DOC_END = "...";
+
+ private void resetBuffer(String str) {
+ _sbuf = str.charAt(str.length() - 1) == '\n' ? str : str + "\n";
+ _index = -1;
+ }
+
+
+ private int _getChar_() {
+ if (_index + 1 < _sbuf.length()) {
+ _index++;
+ } else {
+ String line = getLine();
+ if (line == null) return -1;
+ resetBuffer(line);
+ _index++;
+ }
+ int ch = _sbuf.charAt(_index);
+ return ch;
+ }
+
+ private int getChar() {
+ int ch;
+ do {
+ ch = _getChar_();
+ } while (ch >= 0 && isWhite(ch));
+ return ch;
+ }
+
+ private int getCharOrNewline() {
+ int ch;
+ do {
+ ch = _getChar_();
+ } while (ch >= 0 && isWhite(ch) && ch != '\n');
+ return ch;
+ }
+
+ private int currentChar() {
+ return _sbuf.charAt(_index);
+ }
+
+ private SyntaxException syntaxError(String message, int linenum) {
+ return new YamlSyntaxException(message, linenum);
+ }
+
+ private SyntaxException syntaxError(String message) {
+ return new SyntaxException(message, _linenum);
+ }
+
+ private Object parseChild(int column) throws SyntaxException {
+ String line = getLine();
+ if (line == null) {
+ return createScalar(null);
+ }
+ Matcher m = Util.matcher(line, "^( *)(.*)");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ int indent = m.group(1).length();
+ if (indent < column) {
+ return createScalar(null);
+ }
+ String value = m.group(2);
+ return parseValue(column, value, indent);
+ }
+
+ private Object parseValue(int column, String value, int value_start_column) throws SyntaxException {
+ Object data;
+ if (Util.matches(value, "^-( |$)")) {
+ data = parseSequence(value_start_column, value);
+ } else if (Util.matches(value, "^((?::?[-.\\w]+|'.*?'|\".*?\"|=|<<) *):(( +)(.*))?$")) {
+ data = parseMapping(value_start_column, value);
+ } else if (Util.matches(value, "^[\\[\\{]")) {
+ data = parseFlowStyle(column, value);
+ } else if (Util.matches(value, "^\\&[-\\w]+( |$)")) {
+ data = parseAnchor(column, value);
+ } else if (Util.matches(value, "^\\*[-\\w]+( |$)")) {
+ data = parseAlias(column, value);
+ } else if (Util.matches(value, "^[|>]")) {
+ data = parseBlockText(column, value);
+ } else if (Util.matches(value, "^!")) {
+ data = parseTag(column, value);
+ } else if (Util.matches(value, "^\\#")) {
+ data = parseChild(column);
+ } else {
+ data = parseScalar(column, value);
+ }
+ return data;
+ }
+
+ private static boolean isWhite(int ch) {
+ return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+ }
+
+
+ private Object parseFlowStyle(int column, String value) throws SyntaxException {
+ resetBuffer(value);
+ getChar();
+ Object data = parseFlow(0);
+ int ch = currentChar();
+ assert ch == ']' || ch == '}';
+ ch = getCharOrNewline();
+ if (ch != '\n' && ch != '#' && ch >= 0) {
+ throw syntaxError("flow style sequence is closed buf got '" + ((char)ch) + "'.");
+ }
+ if (ch >= 0) getLine();
+ return data;
+ }
+
+ private Object parseFlow(int depth) throws SyntaxException {
+ int ch = currentChar();
+ //ch = getChar();
+ if (ch < 0) {
+ throw syntaxError("found EOF when parsing flow style.");
+ }
+ Object data;
+ if (ch == '[') {
+ data = parseFlowSequence(depth);
+ } else if (ch == '{') {
+ data = parseFlowMapping(depth);
+ } else {
+ data = parseFlowScalar(depth);
+ }
+ return data;
+ }
+
+ private List parseFlowSequence(int depth) throws SyntaxException {
+ assert currentChar() == '[';
+ List seq = createSequence(_linenum);
+ int ch = getChar();
+ if (ch != '}') {
+ int linenum = currentLineNumber();
+ //seq.add(parseFlowSequenceItem(depth+1);
+ addSequenceValue(seq, parseFlowSequenceItem(depth + 1), linenum);
+ while ((ch = currentChar()) == ',') {
+ ch = getChar();
+ if (ch == '}') {
+ throw syntaxError("sequence item required (or last comma is extra).");
+ }
+ //if (ch == '?') break;
+ linenum = currentLineNumber();
+ //seq.add(parseFlowSequenceItem(depth+1);
+ addSequenceValue(seq, parseFlowSequenceItem(depth + 1), linenum);
+ }
+ }
+ if (currentChar() != ']') {
+ throw syntaxError("flow style sequence requires ']'.");
+ }
+ if (depth > 0) getChar();
+ return seq;
+ }
+
+ private Object parseFlowSequenceItem(int depth) throws SyntaxException {
+ return parseFlow(depth);
+ }
+
+ private Map parseFlowMapping(int depth) throws SyntaxException {
+ assert currentChar() == '{';
+ Map map = createMapping(_linenum);
+ int ch = getChar();
+ if (ch != '}') {
+ int linenum = currentLineNumber();
+ Object[] pair = parseFlowMappingItem(depth + 1);
+ Object key = pair[0];
+ Object value = pair[1];
+ //map[ke] = value
+ setMappingValueWith(map, key, value, linenum);
+ while ((ch = currentChar()) == ',') {
+ ch = getChar();
+ if (ch == '}') {
+ throw syntaxError("mapping item required (or last comman is extra.");
+ }
+ //if (ch == '}') break;
+ linenum = currentLineNumber();
+ pair = parseFlowMappingItem(depth + 1);
+ key = pair[0];
+ value = pair[1];
+ //map.put(key) = value;
+ setMappingValueWith(map, key, value, linenum);
+ }
+ }
+ if (currentChar() != '}') {
+ throw syntaxError("flow style mapping requires '}'.");
+ }
+ if (depth > 0) getChar();
+ return map;
+ }
+
+ private Object[] parseFlowMappingItem(int depth) throws SyntaxException {
+ Object key = parseFlow(depth);
+ int ch = currentChar();
+ if (ch != ':') {
+ String s = ch >= 0 ? "'" + ((char)ch) + "'" : "EOF";
+ throw syntaxError("':' expected but got " + s);
+ }
+ getChar();
+ Object value = parseFlow(depth);
+ return new Object[] { key, value };
+ }
+
+ private Object parseFlowScalar(int depth) throws SyntaxException {
+ int ch = currentChar();
+ Object scalar = null;
+ StringBuffer sb = new StringBuffer();
+ if (ch == '"' || ch == '\'') {
+ int endch = ch;
+ while ((ch = _getChar_()) >= 0 && ch != endch) {
+ sb.append((char)ch);
+ }
+ getChar();
+ scalar = sb.toString();
+ } else {
+ sb.append((char)ch);
+ while ((ch = _getChar_()) >= 0 && ch != ':' && ch != ',' && ch != ']' && ch != '}') {
+ sb.append((char)ch);
+ }
+ scalar = toScalar(sb.toString().trim());
+ }
+ return createScalar(scalar);
+ }
+
+ private Object parseTag(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^!\\S+");
+ Matcher m = Util.matcher(value, "^!(\\S+)((\\s+)(.*))?$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String tag = m.group(1);
+ String space = m.group(3);
+ String value2 = m.group(4);
+ Object data;
+ if (value2 != null && value2.length() > 0) {
+ int value_start_column = column + 1 + tag.length() + space.length();
+ data = parseValue(column, value2, value_start_column);
+ } else {
+ data = parseChild(column);
+ }
+ return data;
+ }
+
+ private Object parseAnchor(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^\\&([-\\w]+)(( *)(.*))?$");
+ Matcher m = Util.matcher(value, "^\\&([-\\w]+)(( *)(.*))?$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String label = m.group(1);
+ String space = m.group(3);
+ String value2 = m.group(4);
+ Object data;
+ if (value2 != null && value2.length() > 0) {
+ int value_start_column = column + 1 + label.length() + space.length();
+ data = parseValue(column, value2, value_start_column);
+ } else {
+ data = parseChild(column);
+ }
+ registerAnchor(label, data);
+ return data;
+ }
+
+ private void registerAnchor(String label, Object data) throws SyntaxException {
+ if (_anchors.containsKey(label)) {
+ throw syntaxError("anchor '" + label + "' is already used.");
+ }
+ _anchors.put(label, data);
+ }
+
+ private Object parseAlias(int column, String value) throws SyntaxException {
+ assert value.matches("^\\*([-\\w]+)(( *)(.*))?$");
+ Matcher m = Util.matcher(value, "^\\*([-\\w]+)(( *)(.*))?$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String label = m.group(1);
+ //String space = m.group(3);
+ String value2 = m.group(4);
+ if (value2 != null && value2.length() > 0 && value2.charAt(0) != '#') {
+ throw syntaxError("alias cannot take any data.");
+ }
+ Object data = _anchors.get(label);
+ if (data == null) {
+ //throw syntaxError("anchor '" + label "' not found (cannot refer to backward or child anchor).");
+ data = registerAlias(label);
+ }
+ getLine();
+ return data;
+ }
+
+ private Alias registerAlias(String label) throws SyntaxException {
+ Integer count = (Integer)_aliases.get(label);
+ if (count == null) {
+ _aliases.put(label, new Integer(1));
+ } else {
+ _aliases.put(label, new Integer(count.intValue() + 1));
+ }
+ return new Alias(label, _linenum);
+ }
+
+
+ private void resolveAliases(Object data) throws SyntaxException { // List or Map
+ Map resolved = new IdentityHashMap();
+ resolveAliases(data, resolved);
+ }
+
+
+ private void resolveAliases(Object data, Map resolved) throws SyntaxException {
+ if (resolved.containsKey(data)) {
+ return;
+ }
+ resolved.put(data, data);
+ if (data instanceof List) {
+ resolveAliases((List)data, resolved);
+ } else if (data instanceof Map) {
+ resolveAliases((Map)data, resolved);
+ } else {
+ assert !(data instanceof Alias);
+ }
+ if (data instanceof Defaultable) {
+ Object default_value = ((Defaultable)data).getDefault();
+ if (default_value != null) {
+ resolveAliases(default_value, resolved);
+ }
+ }
+ }
+
+ private void resolveAliases(List seq, Map resolved) throws SyntaxException {
+ int len = seq.size();
+ for (int i = 0; i < len; i++) { // don't use itrator not to raise java.util.ConcurrentModificationException
+ Object val = seq.get(i);
+ if (val instanceof Alias) {
+ Alias alias = (Alias)val;
+ String label = alias.getLabel();
+ if (_anchors.containsKey(label)) {
+ //seq.set(i, _anchors.get(label);
+ setSequenceValueAt(seq, i, _anchors.get(label), alias.getLineNumber());
+ } else {
+ throw syntaxError("anchor '" + alias.getLabel() + "' not found.");
+ }
+ } else if (val instanceof List || val instanceof Map) {
+ resolveAliases(val, resolved);
+ }
+ }
+ }
+
+ private void resolveAliases(Map map, Map resolved) throws SyntaxException {
+ for (Iterator it = map.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object val = map.get(key);
+ if (val instanceof Alias) {
+ Alias alias = (Alias)val;
+ String label = alias.getLabel();
+ if (_anchors.containsKey(label)) {
+ //map.put(key, _anchors.get(label));
+ setMappingValueWith(map, key, _anchors.get(label), alias.getLineNumber());
+ } else {
+ throw syntaxError("anchor '" + alias.getLabel() + "' not found.", alias.getLineNumber());
+ }
+ } else if (val instanceof List || val instanceof Map) {
+ resolveAliases(val, resolved);
+ }
+ }
+ }
+
+
+
+/*
+ private Object parseBlockText(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^[>|\\|]");
+ Matcher m = Util.matcher(value, "^([>|\\|])([-+]?)\\s*(.*)$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String blockchar = m.group(1);
+ String indicator = m.group(2);
+ String sep = blockchar.equals("|") ? "\n" : " ";
+ //String text = m.group(3).length() > 0 ? "" : m.group(3) + sep;
+ String text = m.group(3);
+ StringBuffer sb = new StringBuffer();
+ StringBuffer empty = new StringBuffer();
+ int min_indent = -1;
+ String line;
+ Pattern pat2 = Pattern.compile("^( *)(.*)");
+ while ((line = _getLine_()) != null) {
+ (m = pat2.matcher(line)).find();
+ int indent = m.group(1).length();
+ if (m.group(2).length() == 0) {
+ empty.append("\n");
+ } else if (indent < column) {
+ break;
+ } else {
+ if (min_indent < 0 || min_indent > indent) {
+ min_indent = indent;
+ }
+ sb.append(empty.toString());
+ sb.append(line);
+ empty.delete(0, empty.length());
+ }
+ }
+ if (indicator.equals("+")) {
+ sb.append(empty);
+ } else if (indicator.equals("-")) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ String s;
+ if (min_indent <= 0) {
+ s = sb.toString();
+ } else {
+ StringBuffer regex = new StringBuffer("(?m)^");
+ for (int i = 0; i < min_indent; i++) regex.append(" ");
+ s = sb.toString().replaceAll(regex.toString(), "");
+ }
+ if (blockchar.equals(">")) {
+ StringBuffer sb2 = new StringBuffer();
+ int len = s.length();
+ int n = 0;
+ for (int i = 0; i < len; i++) {
+ char ch = s.charAt(i);
+ if (ch == '\n') {
+ n++;
+ } else {
+ if (n == 1) {
+ sb2.append(' '); n = 0;
+ } else if (n > 1) {
+ sb2.append('\n'); n = 0;
+ }
+ sb2.append(ch);
+ }
+ }
+ s = sb2.toString();
+ }
+ if (currentLine() != null && Util.matches(currentLine(), "^\\s*#")) getLine();
+ return createScalar(text + s);
+ }
+*/
+
+ private Object parseBlockText(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^[>|]");
+ Matcher m = Util.matcher(value, "^([>|])([-+]?)(\\d*)\\s*(.*)$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ char blockchar = m.group(1).length() > 0 ? m.group(1).charAt(0) : '\0';
+ char indicator = m.group(2).length() > 0 ? m.group(2).charAt(0) : '\0';
+ int indent = m.group(3).length() > 0 ? Integer.parseInt(m.group(3)) : -1;
+ String text = m.group(4);
+ char sep = blockchar == '|' ? '\n' : ' ';
+ String line;
+ StringBuffer sb = new StringBuffer();
+ int n = 0;
+ while ((line = _getLine_()) != null) {
+ m = Util.matcher(line, "^( *)(.*)$");
+ m.find();
+ String space = m.group(1);
+ String str = m.group(2);
+ if (indent < 0) indent = space.length();
+ if (str.length() == 0) { // empty line
+ n++;
+ } else {
+ int slen = space.length();
+ if (slen < column) {
+ break;
+ } else if (slen < indent) {
+ throw syntaxError("invalid indent in block text.");
+ } else {
+ if (n > 0) {
+ if (blockchar == '>' && sb.length() > 0) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ for (int i = 0; i < n; i++) {
+ sb.append('\n');
+ }
+ n = 0;
+ }
+ str = line.substring(indent);
+ }
+ }
+ sb.append(str);
+ if (blockchar == '>') {
+ if (sb.charAt(sb.length() - 1) == '\n') {
+ sb.setCharAt(sb.length() - 1, ' ');
+ }
+ }
+ }
+ if (line != null && Util.matches(line, "^ *#")) {
+ getLine();
+ }
+ switch (indicator) {
+ case '+':
+ if (n > 0) {
+ if (blockchar == '>') {
+ sb.setCharAt(sb.length() - 1, '\n');
+ }
+ for (int i = 0; i < n; i++) {
+ sb.append('\n');
+ }
+ }
+ break;
+ case '-':
+ if (sb.charAt(sb.length() - 1) == sep) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ break;
+ default:
+ if (blockchar == '>') {
+ sb.setCharAt(sb.length() - 1, '\n');
+ }
+ }
+ return createScalar(text + sb.toString());
+ }
+
+
+ private List parseSequence(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^-(( +)(.*))?$");
+ List seq = createSequence(_linenum);
+ while (true) {
+ Matcher m = Util.matcher(value, "^-(( +)(.*))?$");
+ if (! m.find()) {
+ throw syntaxError("sequence item is expected.");
+ }
+ String space = m.group(2);
+ String value2 = m.group(3);
+ int column2 = column + 1;
+ int linenum = currentLineNumber();
+ //
+ Object elem;
+ if (value2 == null || value2.length() == 0) {
+ elem = parseChild(column2);
+ } else {
+ int value_start_column = column2 + space.length();
+ elem = parseValue(column2, value2, value_start_column);
+ }
+ addSequenceValue(seq, elem, linenum);
+ //
+ String line = currentLine();
+ if (line == null) break;
+ Matcher m2 = Util.matcher(line, "^( *)(.*)");
+ m2.find();
+ int indent = m2.group(1).length();
+ if (indent < column) {
+ break;
+ } else if (indent > column) {
+ throw syntaxError("invalid indent of sequence.");
+ }
+ value = m2.group(2);
+ }
+ return seq;
+ }
+
+
+ private Map parseMapping(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^((?::?[-.\\w]+|'.*?'|\".*?\"|=|<<) *):(( +)(.*))?$");
+ Map map = createMapping(_linenum);
+ while (true) {
+ Matcher m = Util.matcher(value, "^((?::?[-.\\w]+|'.*?'|\".*?\"|=|<<) *):(( +)(.*))?$");
+ if (! m.find()) {
+ throw syntaxError("mapping item is expected.");
+ }
+ String v = m.group(1).trim();
+ Object key = toScalar(v);
+ String value2 = m.group(4);
+ int column2 = column + 1;
+ int linenum = currentLineNumber();
+ //
+ Object elem;
+ if (value2 == null || value2.length() == 0) {
+ elem = parseChild(column2);
+ } else {
+ int value_start_column = column2 + m.group(1).length() + m.group(3).length();
+ elem = parseValue(column2, value2, value_start_column);
+ }
+ if (v.equals("=")) {
+ setMappingDefault(map, elem, linenum);
+ } else if (v.equals("<<")) {
+ mergeCollection(map, elem, linenum);
+ } else {
+ setMappingValueWith(map, key, elem, linenum);
+ }
+ //
+ String line = currentLine();
+ if (line == null) {
+ break;
+ }
+ Matcher m2 = Util.matcher(line, "^( *)(.*)");
+ m2.find();
+ int indent = m2.group(1).length();
+ if (indent < column) {
+ break;
+ } else if (indent > column) {
+ throw syntaxError("invalid indent of mapping.");
+ }
+ value = m2.group(2);
+ }
+ return map;
+ }
+
+
+ private Object parseScalar(int indent, String value) throws SyntaxException {
+ Object data = createScalar(toScalar(value));
+ getLine();
+ return data;
+ }
+
+
+ private Object toScalar(String value) {
+ Matcher m;
+ if ((m = Util.matcher(value, "^\"(.*)\"([ \t]*#.*$)?")).find()) {
+ return m.group(1);
+ } else if ((m = Util.matcher(value, "^'(.*)'([ \t]*#.*$)?")).find()) {
+ return m.group(1);
+ } else if ((m = Util.matcher(value, "^(.*\\S)[ \t]*#")).find()) {
+ value = m.group(1);
+ }
+ //
+ if (Util.matches(value, "^-?0x\\d+$")) return new Integer(Integer.parseInt(value, 16));
+ else if (Util.matches(value, "^-?0\\d+$")) return new Integer(Integer.parseInt(value, 8));
+ else if (Util.matches(value, "^-?\\d+$")) return new Integer(Integer.parseInt(value, 10));
+ else if (Util.matches(value, "^-?\\d+\\.\\d+$")) return new Double(Double.parseDouble(value));
+ else if (Util.matches(value, "^(true|yes|on)$")) return Boolean.TRUE;
+ else if (Util.matches(value, "^(false|no|off)$")) return Boolean.FALSE;
+ else if (Util.matches(value, "^(null|~)$")) return null;
+ else if (Util.matches(value, "^:(\\w+)$")) return value;
+ else if ((m = Util.matcher(value, "^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)$")).find()) {
+ int year = Integer.parseInt(m.group(1));
+ int month = Integer.parseInt(m.group(2));
+ int day = Integer.parseInt(m.group(3));
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day, 0, 0, 0);
+ Date date = cal.getTime();
+ return date;
+ } else if ((m = Util.matcher(value, "^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)(?:[Tt]|[ \t]+)(\\d\\d?):(\\d\\d):(\\d\\d)(\\.\\d*)?(?:Z|[ \t]*([-+]\\d\\d?)(?::(\\d\\d))?)?$")).find()) {
+ int year = Integer.parseInt(m.group(1));
+ int month = Integer.parseInt(m.group(2));
+ int day = Integer.parseInt(m.group(3));
+ int hour = Integer.parseInt(m.group(4));
+ int min = Integer.parseInt(m.group(5));
+ int sec = Integer.parseInt(m.group(6));
+ //int usec = Integer.parseInt(m.group(7));
+ //int tzone_h = Integer.parseInt(m.group(8));
+ //int tzone_m = Integer.parseInt(m.group(9));
+ String timezone = "GMT" + m.group(8) + ":" + m.group(9);
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day, hour, min, sec);
+ cal.setTimeZone(TimeZone.getTimeZone(timezone));
+ Date date = cal.getTime();
+ return date;
+ } else {
+ return value;
+ }
+ }
+
+/*
+ public static void main(String[] args) throws Exception {
+ String filename = args.length > 0 ? args[0] : "test.yaml";
+ String s = Util.readFile(filename);
+ PlainYamlParser parser = new PlainYamlParser(s);
+ while (parser.hasNext()) {
+ Object doc = parser.parse();
+ System.out.println(Util.inspect(doc));
+ }
+ }
+*/
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Rule.java b/javatoscachecker/kwalify/src/main/java/kwalify/Rule.java
new file mode 100644
index 0000000..558525d
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Rule.java
@@ -0,0 +1,673 @@
+/*
+ * @(#)Rule.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * rule for validation.
+ * Validator class generates rule instances.
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class Rule {
+
+ /*
+ * instance variables
+ */
+
+ private Rule _parent;
+ private String _name = null;
+ private String _desc = null;
+ private String _short = null; //added by jora: only used for map types
+ private String _ref = null; //added by jora: only used for ref types (references to other rules by name)
+ private boolean _required = false;
+ private String _type = null;
+ private Class _type_class = null;
+ private String _pattern = null;
+ private Pattern _pattern_regexp = null;
+ private List _enum = null;
+ private List _sequence = null;
+ private DefaultableHashMap _mapping = null;
+ private String _assert = null;
+ private Map _range = null;
+ private Map _length = null;
+ private boolean _ident = false;
+ private boolean _unique = false;
+
+
+ /*
+ * accessors
+ */
+
+ public String getName() { return _name; }
+ public void setName(String name) { _name = name; }
+
+ public String getDesc() { return _desc; }
+ public void setDesc(String desc) { _desc = desc; }
+
+ public String getShort() { return _short; }
+ public void setShort(String val) { _short = val; }
+
+ public String getReference() { return _ref; }
+ public void setReference(String ref) { _ref = ref; }
+
+ public boolean isRequired() { return _required; }
+ public void setRequired(boolean required) { _required = required; }
+
+ public String getType() { return _type; }
+ public void setType(String type) { _type = type; }
+
+ public Class getTypeClass() { return _type_class; }
+ public void setTypeClass(Class type_class) { _type_class = type_class; }
+
+ public String getPattern() { return _pattern; }
+ public void setPattern(String pattern) { _pattern = pattern; }
+
+ public Pattern getPatternRegexp() { return _pattern_regexp; }
+ public void setPatternRegexp(Pattern patternRegexp) { _pattern_regexp = patternRegexp; }
+
+ public List getEnum() { return _enum; }
+ public void setEnum(List enumList) { _enum = enumList; }
+
+ public List getSequence() { return _sequence; }
+ public void setSequence(List sequence) { _sequence = sequence; }
+
+ public DefaultableHashMap getMapping() { return _mapping; }
+ public void setMapping(DefaultableHashMap mapping) { _mapping = mapping; }
+
+ public String getAssert() { return _assert; }
+ public void setAssert(String assertString) { _assert = assertString; }
+
+ public Map getRange() { return _range; }
+ public void setRange(Map range) { _range = range; }
+
+ public Map getLength() { return _length; }
+ public void setLength(Map length) { _length = length; }
+
+ public boolean isIdent() { return _ident; }
+ public void setIdent(boolean ident) { _ident = ident; }
+
+ public boolean isUnique() { return _unique; }
+ public void setUnique(boolean unique) { _unique = unique; }
+
+
+ /*
+ * constructors
+ */
+
+ public Rule(Object schema, Rule parent) throws SchemaException {
+ if (schema != null) {
+ if (! (schema instanceof Map)) {
+ throw schemaError("schema.notmap", null, "/", null, null);
+ }
+ Map rule_table = new IdentityHashMap();
+ init((Map)schema, "", rule_table);
+ }
+ _parent = parent;
+ }
+
+ public Rule(Object schema) throws SchemaException {
+ this(schema, null);
+ }
+
+ public Rule(Map schema, Rule parent) throws SchemaException {
+ if (schema != null) {
+ Map rule_table = new IdentityHashMap();
+ init(schema, "", rule_table);
+ }
+ _parent = parent;
+ }
+
+ public Rule(Map schema) throws SchemaException {
+ this(schema, null);
+ }
+
+ public Rule() throws SchemaException {
+ this(null, null);
+ }
+
+ /*
+ * constants
+ */
+
+ private static final int CODE_NAME = "name".hashCode();
+ private static final int CODE_DESC = "desc".hashCode();
+ private static final int CODE_SHORT = "short".hashCode(); //jora
+ private static final int CODE_RULE = "rule".hashCode(); //jora
+ private static final int CODE_REQUIRED = "required".hashCode();
+ private static final int CODE_TYPE = "type".hashCode();
+ private static final int CODE_PATTERN = "pattern".hashCode();
+ private static final int CODE_ENUM = "enum".hashCode();
+ private static final int CODE_SEQUENCE = "sequence".hashCode();
+ private static final int CODE_MAPPING = "mapping".hashCode();
+ private static final int CODE_ASSERT = "assert".hashCode();
+ private static final int CODE_RANGE = "range".hashCode();
+ private static final int CODE_LENGTH = "length".hashCode();
+ private static final int CODE_IDENT = "ident".hashCode();
+ private static final int CODE_UNIQUE = "unique".hashCode();
+
+
+
+ /*
+ * instance methods
+ */
+ public Rule getParent() { // by jora
+ return this._parent;
+ }
+
+
+ private static SchemaException schemaError(String errorSymbol, Rule rule, String path, Object value, Object[] args) {
+ String msg = Messages.buildMessage(errorSymbol, value, args);
+ return new SchemaException(msg, path, value, rule, errorSymbol);
+ }
+
+
+ private void init(Object elem, String path, Map rule_table) throws SchemaException {
+ assert elem != null;
+ if (! (elem instanceof Map)) {
+ if (path == null || path.equals("")) {
+ path = "/";
+ }
+ throw schemaError("schema.notmap", null, path, null, null);
+ }
+ init((Map)elem, path, rule_table);
+
+ }
+
+
+ private void init(Map hash, String path, Map rule_table) throws SchemaException {
+ Rule rule = this;
+ rule_table.put(hash, rule);
+
+ // 'type:' entry
+ Object type = hash.get("type");
+ initTypeValue(type, rule, path);
+
+ // other entries
+ for (Iterator it = hash.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object value = hash.get(key);
+ int code = key.hashCode();
+
+ if (code == CODE_TYPE && key.equals("type")) {
+ // done
+ } else if (code == CODE_NAME && key.equals("name")) {
+ initNameValue(value, rule, path);
+ } else if (code == CODE_DESC && key.equals("desc")) {
+ initDescValue(value, rule, path);
+ } else if (code == CODE_SHORT && key.equals("short")) {
+ initShortValue(value, rule, path);
+ } else if (code == CODE_REQUIRED && key.equals("required")) {
+ initRequiredValue(value, rule, path);
+ } else if (code == CODE_PATTERN && key.equals("pattern")) {
+ initPatternValue(value, rule, path);
+ } else if (code == CODE_ENUM && key.equals("enum")) {
+ initEnumValue(value, rule, path);
+ } else if (code == CODE_ASSERT && key.equals("assert")) {
+ initAssertValue(value, rule, path);
+ } else if (code == CODE_RANGE && key.equals("range")) {
+ initRangeValue(value, rule, path);
+ } else if (code == CODE_LENGTH && key.equals("length")) {
+ initLengthValue(value, rule, path);
+ } else if (code == CODE_IDENT && key.equals("ident")) {
+ initIdentValue(value, rule, path);
+ } else if (code == CODE_UNIQUE && key.equals("unique")) {
+ initUniqueValue(value, rule, path);
+ } else if (code == CODE_SEQUENCE && key.equals("sequence")) {
+ rule = initSequenceValue(value, rule, path, rule_table);
+ } else if (code == CODE_MAPPING && key.equals("mapping")) {
+ rule = initMappingValue(value, rule, path, rule_table);
+ } else if (code == CODE_RULE && key.equals("rule")) {
+ rule = initReferenceValue(value, rule, path, rule_table);
+ } else {
+ // removed by 'jora': interferes with the usage of YAML anchor/alias in grammar files
+ // throw schemaError("key.unknown", rule, path + "/" + key, key.toString() + ":", null);
+ }
+ }
+
+ // confliction check
+ checkConfliction(hash, rule, path);
+ }
+
+
+ private void initTypeValue(Object value, Rule rule, String path) throws SchemaException {
+ if (value == null) {
+ value = Types.getDefaultType();
+ }
+ if (! (value instanceof String)) {
+ throw schemaError("type.notstr", rule, path + "/type", _type, null);
+ }
+ _type = (String)value;
+ _type_class = Types.typeClass(_type);
+ if (! Types.isBuiltinType(_type)) {
+ throw schemaError("type.unknown", rule, path + "/type", _type, null);
+ }
+ }
+
+
+ private void initNameValue(Object value, Rule rule, String path) throws SchemaException {
+ _name = value.toString();
+ }
+
+
+ private void initDescValue(Object value, Rule rule, String path) throws SchemaException {
+ _desc = value.toString();
+ }
+
+ private void initShortValue(Object value, Rule rule, String path) throws SchemaException {
+
+ //the short form specification is to be interpreted as key if the type is a map or as an
+ //index if the target is a sequence (as index 0 actually)
+ if (!Types.isCollectionType(_type)) {
+ throw schemaError("range.notcollection", rule, path + "/short", value, null);
+ }
+ //we should also verify that it points to a declared key of the mapping .. not really, as it would
+ //fail the overall grammar
+ _short = value.toString();
+ }
+
+ private void initRequiredValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof Boolean)) {
+ throw schemaError("required.notbool", rule, path + "/required", value, null);
+ }
+ _required = ((Boolean)value).booleanValue();
+ }
+
+
+ private void initPatternValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof String)) {
+ throw schemaError("pattern.notstr", rule, path + "/pattern", value, null);
+ }
+ _pattern = (String)value;
+ Matcher m = Util.matcher(_pattern, "\\A/(.*)/([mi]?[mi]?)\\z");
+ if (! m.find()) {
+ throw schemaError("pattern.notmatch", rule, path + "/pattern", value, null);
+ }
+ String pat = m.group(1);
+ String opt = m.group(2);
+ int flag = 0;
+ if (opt.indexOf('i') >= 0) {
+ flag += Pattern.CASE_INSENSITIVE;
+ }
+ if (opt.indexOf('m') >= 0) {
+ flag += Pattern.DOTALL; // not MULTILINE
+ }
+ try {
+ _pattern_regexp = Pattern.compile(pat, flag);
+ } catch (PatternSyntaxException ex) {
+ throw schemaError("pattern.syntaxerr", rule, path + "/pattern", value, null);
+ }
+ }
+
+
+ private void initEnumValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof List)) {
+ throw schemaError("enum.notseq", rule, path + "/enum", value, null);
+ }
+ _enum = (List)value;
+ if (Types.isCollectionType(_type)) {
+ throw schemaError("enum.notscalar", rule, path, "enum:", null);
+ }
+ Map elem_table = new HashMap();
+ for (Iterator it = _enum.iterator(); it.hasNext(); ) {
+ Object elem = it.next();
+ if (! Util.isInstanceOf(elem, _type_class)) {
+ throw schemaError("enum.type.unmatch", rule, path + "/enum", elem, new Object[] { Types.typeName(_type) });
+ }
+ if (elem_table.containsKey(elem)) {
+ throw schemaError("enum.duplicate", rule, path + "/enum", elem, null);
+ }
+ elem_table.put(elem, Boolean.TRUE);
+ }
+ }
+
+
+ private void initAssertValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof String)) {
+ throw schemaError("assert.notstr", rule, path + "/assert", value, null);
+ }
+ _assert = (String)value;
+ if (! Util.matches(_assert, "\\bval\\b")) {
+ throw schemaError("assert.noval", rule, path + "/assert", value, null);
+ }
+ }
+
+
+ private void initRangeValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof Map)) {
+ throw schemaError("range.notmap", rule, path + "/range", value, null);
+ }
+ if (Types.isCollectionType(_type) || _type.equals("bool")) {
+ throw schemaError("range.notscalar", rule, path, "range:", null);
+ }
+ _range = (Map)value;
+ for (Iterator it = _range.keySet().iterator(); it.hasNext(); ) {
+ Object rkey = it.next();
+ Object rval = _range.get(rkey);
+ if (rkey.equals("max") || rkey.equals("min") || rkey.equals("max-ex") || rkey.equals("min-ex")) {
+ if (! Util.isInstanceOf(rval, _type_class)) {
+ String typename = Types.typeName(_type);
+ throw schemaError("range.type.unmatch", rule, path + "/range/" + rkey, rval, new Object[] { typename });
+ }
+ } else {
+ throw schemaError("range.undefined", rule, path + "/range/" + rkey, rkey.toString() + ":", null);
+ }
+ }
+ if (_range.containsKey("max") && _range.containsKey("max-ex")) {
+ throw schemaError("range.twomax", rule, path + "/range", null, null);
+ }
+ if (_range.containsKey("min") && _range.containsKey("min-ex")) {
+ throw schemaError("range.twomin", rule, path + "/range", null, null);
+ }
+ //
+ Object max = _range.get("max");
+ Object min = _range.get("min");
+ Object max_ex = _range.get("max-ex");
+ Object min_ex = _range.get("min-ex");
+ Object[] args = null;
+ //String error_symbol = null;
+ if (max != null) {
+ if (min != null && Util.compareValues(max, min) < 0) {
+ args = new Object[] { max, min };
+ throw schemaError("range.maxltmin", rule, path + "/range", null, args);
+ } else if (min_ex != null && Util.compareValues(max, min_ex) <= 0) {
+ args = new Object[] { max, min_ex };
+ throw schemaError("range.maxleminex", rule, path + "/range", null, args);
+ }
+ } else if (max_ex != null) {
+ if (min != null && Util.compareValues(max_ex, min) <= 0) {
+ args = new Object[] { max_ex, min };
+ throw schemaError("range.maxexlemin", rule, path + "/range", null, args);
+ } else if (min_ex != null && Util.compareValues(max_ex, min_ex) <= 0) {
+ args = new Object[] { max_ex, min_ex };
+ throw schemaError("range.maxexleminex", rule, path + "/range", null, args);
+ }
+ }
+ }
+
+
+ private void initLengthValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof Map)) {
+ throw schemaError("length.notmap", rule, path + "/length", value, null);
+ }
+ _length = (Map)value;
+ if (! (_type.equals("str") || _type.equals("text"))) {
+ throw schemaError("length.nottext", rule, path, "length:", null);
+ }
+ for (Iterator it = _length.keySet().iterator(); it.hasNext(); ) {
+ Object k = it.next();
+ Object v = _length.get(k);
+ if (k.equals("max") || k.equals("min") || k.equals("max-ex") || k.equals("min-ex")) {
+ if (! (v instanceof Integer)) {
+ throw schemaError("length.notint", rule, path + "/length/" + k, v, null);
+ }
+ } else {
+ throw schemaError("length.undefined", rule, path + "/length/" + k, k + ":", null);
+ }
+ }
+ if (_length.containsKey("max") && _length.containsKey("max-ex")) {
+ throw schemaError("length.twomax", rule, path + "/length", null, null);
+ }
+ if (_length.containsKey("min") && _length.containsKey("min-ex")) {
+ throw schemaError("length.twomin", rule, path + "/length", null, null);
+ }
+ //
+ Integer max = (Integer)_length.get("max");
+ Integer min = (Integer)_length.get("min");
+ Integer max_ex = (Integer)_length.get("max-ex");
+ Integer min_ex = (Integer)_length.get("min-ex");
+ Object[] args = null;
+ //String error_symbol = null;
+ if (max != null) {
+ if (min != null && max.compareTo(min) < 0) {
+ args = new Object[] { max, min };
+ throw schemaError("length.maxltmin", rule, path + "/length", null, args);
+ } else if (min_ex != null && max.compareTo(min_ex) <= 0) {
+ args = new Object[] { max, min_ex };
+ throw schemaError("length.maxleminex", rule, path + "/length", null, args);
+ }
+ } else if (max_ex != null) {
+ if (min != null && max_ex.compareTo(min) <= 0) {
+ args = new Object[] { max_ex, min };
+ throw schemaError("length.maxexlemin", rule, path + "/length", null, args);
+ } else if (min_ex != null && max_ex.compareTo(min_ex) <= 0) {
+ args = new Object[] { max_ex, min_ex };
+ throw schemaError("length.maxexleminex", rule, path + "/length", null, args);
+ }
+ }
+ }
+
+
+ private void initIdentValue(Object value, Rule rule, String path) throws SchemaException {
+ if (value == null || ! (value instanceof Boolean)) {
+ throw schemaError("ident.notbool", rule, path + "/ident", value, null);
+ }
+ _ident = ((Boolean)value).booleanValue();
+ _required = true;
+ if (Types.isCollectionType(_type)) {
+ throw schemaError("ident.notscalar", rule, path, "ident:", null);
+ }
+ if (path.equals("")) {
+ throw schemaError("ident.onroot", rule, "/", "ident:", null);
+ }
+ if (_parent == null || ! _parent.getType().equals("map")) {
+ throw schemaError("ident.notmap", rule, path, "ident:", null);
+ }
+ }
+
+
+ private void initUniqueValue(Object value, Rule rule, String path) throws SchemaException {
+ if (! (value instanceof Boolean)) {
+ throw schemaError("unique.notbool", rule, path + "/unique", value, null);
+ }
+ _unique = ((Boolean)value).booleanValue();
+ if (Types.isCollectionType(_type)) {
+ throw schemaError("unique.notscalar", rule, path, "unique:", null);
+ }
+ if (path.equals("")) {
+ throw schemaError("unique.onroot", rule, "/", "unique:", null);
+ }
+ //if (_parent == null || _parent.getType() == "map") {
+ // throw schemaError("sequence.notseq", rule, path + "/unique", value);
+ //}
+ }
+
+
+ private Rule initSequenceValue(Object value, Rule rule, String path, Map rule_table) throws SchemaException {
+ if (value != null && ! (value instanceof List)) {
+ throw schemaError("sequence.notseq", rule, path + "/sequence", value.toString(), null);
+ }
+ _sequence = (List)value;
+ if (_sequence == null || _sequence.size() == 0) {
+ throw schemaError("sequence.noelem", rule, path + "/sequence", value, null);
+ }
+ if (_sequence.size() > 1) {
+ throw schemaError("sequence.toomany", rule, path + "/sequence", value, null);
+ }
+ Object elem = _sequence.get(0);
+ if (elem == null) {
+ elem = new HashMap();
+ }
+ int i = 0;
+ // Rule rule;
+ rule = (Rule)rule_table.get(elem);
+ if (rule == null) {
+ rule = new Rule(null, this);
+ rule.init(elem, path + "/sequence/" + i, rule_table);
+ }
+ _sequence = new ArrayList();
+ _sequence.add(rule);
+ return rule;
+ }
+
+
+ private Rule initMappingValue(Object value, Rule rule, String path, Map rule_table) throws SchemaException {
+
+ // error check
+ if (value != null && !(value instanceof Map)) {
+ throw schemaError("mapping.notmap", rule, path + "/mapping", value.toString(), null);
+ }
+ Object default_value = null;
+ if (value instanceof Defaultable) {
+ default_value = ((Defaultable)value).getDefault();
+ }
+ if (value == null || ((Map)value).size() == 0 && default_value == null) {
+ throw schemaError("mapping.noelem", rule, path + "/mapping", value, null);
+ }
+ // create hash of rule
+ _mapping = new DefaultableHashMap();
+ if (default_value != null) {
+ rule = (Rule)rule_table.get(default_value);
+ if (rule == null) {
+ rule = new Rule(null, this);
+ rule.init(default_value, path + "/mapping/=", rule_table);
+ }
+ _mapping.setDefault(rule);
+ }
+ // put rules into _mapping
+ Map map = (Map)value;
+ for (Iterator it = map.keySet().iterator(); it.hasNext(); ) {
+ Object k = it.next();
+ Object v = map.get(k); // DefaultableHashMap
+ if (v == null) {
+ v = new DefaultableHashMap();
+ }
+ rule = (Rule)rule_table.get(v);
+ if (rule == null) {
+ rule = new Rule(null, this);
+ rule.init(v, path + "/mapping/" + k, rule_table);
+ }
+ if (k.equals("=")) {
+ _mapping.setDefault(rule);
+ } else {
+ _mapping.put(k, rule);
+ }
+ }
+ return rule;
+ }
+
+ private Rule initReferenceValue(Object value, Rule rule, String path, Map rule_table) throws SchemaException {
+
+ this._ref = (String)value;
+ if (this._ref == null)
+ throw schemaError("required.novalue", rule, path, "rule", null);
+ //make sure a rule with this name is in scope
+ Rule refed = (Rule)
+ rule_table.values().stream()
+ .filter(val -> ((Rule)val).getName() != null && ((Rule)val).getName().equals(this._ref))
+ .findFirst()
+ .orElse(null);
+ if (null == refed)
+ throw schemaError("ref.nosuchrule", rule, path, "reference", new Object[] { value });
+
+ return rule;
+ }
+
+ private void checkConfliction(Map hash, Rule rule, String path) {
+ if (_type.equals("seq")) {
+ if (! hash.containsKey("sequence")) throw schemaError("seq.nosequence", rule, path, null, null);
+ if (_enum != null) throw schemaError("seq.conflict", rule, path, "enum:", null);
+ if (_pattern != null) throw schemaError("seq.conflict", rule, path, "pattern:", null);
+ if (_mapping != null) throw schemaError("seq.conflict", rule, path, "mapping:", null);
+ if (_range != null) throw schemaError("seq.conflict", rule, path, "range:", null);
+ if (_length != null) throw schemaError("seq.conflict", rule, path, "length:", null);
+ } else if (_type.equals("map")) {
+ if (! hash.containsKey("mapping")) throw schemaError("map.nomapping", rule, path, null, null);
+ if (_enum != null) throw schemaError("map.conflict", rule, path, "enum:", null);
+ if (_pattern != null) throw schemaError("map.conflict", rule, path, "pattern:", null);
+ if (_sequence != null) throw schemaError("map.conflict", rule, path, "sequence:", null);
+ if (_range != null) throw schemaError("map.conflict", rule, path, "range:", null);
+ if (_length != null) throw schemaError("map.conflict", rule, path, "length:", null);
+ } else {
+ if (_sequence != null) throw schemaError("scalar.conflict", rule, path, "sequence:", null);
+ if (_mapping != null) throw schemaError("scalar.conflict", rule, path, "mapping:", null);
+ if (_enum != null) {
+ if (_range != null) throw schemaError("enum.conflict", rule, path, "range:", null);
+ if (_length != null) throw schemaError("enum.conflict", rule, path, "length:", null);
+ if (_pattern != null) throw schemaError("enum.conflict", rule, path, "pattern:", null);
+ }
+ }
+ }
+
+
+ public String inspect() {
+ StringBuffer sb = new StringBuffer();
+ int level = 0;
+ Map done = new IdentityHashMap();
+ inspect(sb, level, done);
+ return sb.toString();
+ }
+
+ private void inspect(StringBuffer sb, int level, Map done) {
+ done.put(this, Boolean.TRUE);
+ String indent = Util.repeatString(" ", level);
+ if (_name != null) { sb.append(indent).append("name: ").append(_name).append("\n"); }
+ if (_desc != null) { sb.append(indent).append("desc: ").append(_desc).append("\n"); }
+ if (_type != null) { sb.append(indent).append("type: ").append(_type).append("\n"); }
+ if (_required) { sb.append(indent).append("required: ").append(_required).append("\n"); }
+ if (_pattern != null) { sb.append(indent).append("pattern: ").append(_pattern).append("\n"); }
+ if (_pattern_regexp != null) { sb.append(indent).append("regexp: ").append(_pattern_regexp).append("\n"); }
+ if (_assert != null) { sb.append(indent).append("assert: ").append(_assert).append("\n"); }
+ if (_ident) { sb.append(indent).append("ident: ").append(_ident).append("\n"); }
+ if (_unique) { sb.append(indent).append("unique: ").append(_unique).append("\n"); }
+ if (_enum != null) {
+ sb.append(indent).append("enum:\n");
+ for (Iterator it = _enum.iterator(); it.hasNext(); ) {
+ sb.append(indent).append(" - ").append(it.next().toString()).append("\n");
+ }
+ }
+ if (_range != null) {
+ sb.append(indent).append("range: { ");
+ String[] keys = new String[] { "max", "max-ex", "min", "min-ex", };
+ String colon = "";
+ for (int i = 0; i < keys.length; i++) {
+ Object val = _range.get(keys[i]);
+ if (val != null) {
+ sb.append(colon).append(keys[i]).append(": ").append(val);
+ colon = ", ";
+ }
+ }
+ sb.append(" }\n");
+ }
+ if (_sequence != null) {
+ for (Iterator it = _sequence.iterator(); it.hasNext(); ) {
+ Rule rule = (Rule)it.next();
+ if (done.containsKey(rule)) {
+ sb.append(indent).append(" ").append("- ...\n");
+ } else {
+ sb.append(indent).append(" ").append("- \n");
+ rule.inspect(sb, level + 2, done);
+ }
+ }
+ }
+ if (_mapping != null) {
+ for (Iterator it = _mapping.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry entry = (Map.Entry)it.next();
+ Object key = entry.getKey();
+ Rule rule = (Rule)entry.getValue();
+ sb.append(indent).append(" ").append(Util.inspect(key));
+ if (done.containsKey(rule)) {
+ sb.append(": ...\n");
+ } else {
+ sb.append(":\n");
+ rule.inspect(sb, level + 2, done);
+ }
+ }
+ }
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/SchemaException.java b/javatoscachecker/kwalify/src/main/java/kwalify/SchemaException.java
new file mode 100644
index 0000000..5d53bd1
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/SchemaException.java
@@ -0,0 +1,22 @@
+/*
+ * @(#)SchemaException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown by Rule constructor
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class SchemaException extends BaseException {
+ private static final long serialVersionUID = 4750598728284538818L;
+
+ public SchemaException(String message, String ypath, Object value, Rule rule, String errorSymbol) {
+ super(message, ypath, value, rule, errorSymbol);
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/SyntaxException.java b/javatoscachecker/kwalify/src/main/java/kwalify/SyntaxException.java
new file mode 100644
index 0000000..8c36b66
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/SyntaxException.java
@@ -0,0 +1,28 @@
+/*
+ * @(#)SyntaxException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown by parser when syntax is wrong.
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ * @see Parser, YamlSyntaxException
+ */
+public class SyntaxException extends KwalifyException {
+ private static final long serialVersionUID = 2480059811372002740L;
+
+ private int _linenum;
+
+ public SyntaxException(String message, int linenum) {
+ super(message);
+ _linenum = linenum;
+ }
+
+ public int getLineNumber() { return _linenum; }
+ public void setLineNumber(int linenum) { _linenum = linenum; }
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Types.java b/javatoscachecker/kwalify/src/main/java/kwalify/Types.java
new file mode 100644
index 0000000..fbe655c
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Types.java
@@ -0,0 +1,107 @@
+/*
+ * @(#)Types.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Date;
+
+/**
+ * utility methods for type (str, int, ...).
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class Types {
+
+ public static Class typeClass(String type) {
+ return (Class)__type_classes.get(type);
+ }
+
+ public static String typeName(String type) {
+ String name = (String)__type_names.get(type);
+ if (name == null) name = type;
+ return name;
+ }
+
+ public static final String DEFAULT_TYPE = "str";
+
+ public static String getDefaultType() { return DEFAULT_TYPE; }
+
+ private static Map __type_classes;
+ private static Map __type_names;
+ static {
+ //
+ __type_classes = new HashMap();
+ __type_classes.put("str", String.class);
+ __type_classes.put("int", Integer.class);
+ __type_classes.put("float", Double.class);
+ __type_classes.put("number", Number.class);
+ __type_classes.put("text", null);
+ __type_classes.put("bool", Boolean.class);
+ __type_classes.put("map", Map.class);
+ __type_classes.put("seq", List.class);
+ __type_classes.put("timestamp", Date.class);
+ __type_classes.put("date", Date.class);
+ __type_classes.put("symbol", String.class);
+ __type_classes.put("scalar", null);
+ __type_classes.put("any", Object.class);
+ __type_classes.put("ref", Object.class); // by jora
+ //__type_classes.put("null", null);
+
+ //
+ __type_names = new HashMap();
+ __type_names.put("map", "mapping");
+ __type_names.put("seq", "sequence");
+ __type_names.put("str", "string");
+ __type_names.put("int", "integer");
+ __type_names.put("bool", "boolean");
+ __type_names.put("ref", "reference"); //by jora
+ }
+
+
+ public static boolean isBuiltinType(String type) {
+ return __type_classes.containsKey(type);
+ }
+
+ public static boolean isCollectionType(String type) {
+ return type.equals("map") || type.equals("seq");
+ }
+
+ public static boolean isMapType(String type) {
+ return type.equals("map");
+ }
+
+ public static boolean isScalarType(String type) {
+ return !isCollectionType(type);
+ }
+
+ public static boolean isCollection(Object obj) {
+ return obj instanceof Map || obj instanceof List;
+ }
+
+ public static boolean isScalar(Object obj) {
+ return !isCollection(obj);
+ }
+
+ public static boolean isCorrectType(Object obj, String type) {
+ Class type_class = typeClass(type);
+ if (type_class != null) {
+ return type_class.isInstance(obj);
+ }
+ if (type.equals("null")) {
+ return obj == null;
+ } else if (type.equals("text")) {
+ return obj instanceof String || obj instanceof Number;
+ } else if (type.equals("scalar")) {
+ return obj instanceof Number || obj instanceof String || obj instanceof Boolean || obj instanceof Date;
+ }
+ return false;
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Util.java b/javatoscachecker/kwalify/src/main/java/kwalify/Util.java
new file mode 100644
index 0000000..c27c947
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Util.java
@@ -0,0 +1,646 @@
+/*
+ * @(#)Util.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.Date;
+import java.io.Reader;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.io.File;
+
+
+/**
+ * set of utility methods
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+
+public class Util {
+
+ /**
+ * inspect List or Map
+ */
+ public static String inspect(Object obj) {
+ StringBuffer sb = new StringBuffer();
+ inspect(obj, sb, null);
+ return sb.toString();
+ }
+
+ private static void inspect(Object obj, StringBuffer sb, Map done) {
+ if (obj == null) {
+ sb.append("nil"); // null?
+ } else if (obj instanceof String) {
+ inspect((String)obj, sb, done);
+ } else if (obj instanceof Map) {
+ if (done == null) {
+ done = new IdentityHashMap();
+ }
+ if (done.containsKey(obj)) {
+ sb.append("{...}");
+ } else {
+ done.put(obj, Boolean.TRUE);
+ inspect((Map)obj, sb, done);
+ }
+ } else if (obj instanceof List) {
+ if (done == null) {
+ done = new IdentityHashMap();
+ }
+ if (done.containsKey(obj)) {
+ sb.append("[...]");
+ } else {
+ done.put(obj, Boolean.TRUE);
+ inspect((List)obj, sb, done);
+ }
+ } else {
+ sb.append(obj.toString());
+ }
+ }
+
+ private static void inspect(Map map, StringBuffer sb, Map done) {
+ sb.append('{');
+ List list = new ArrayList(map.keySet());
+ Collections.sort(list);
+ int i = 0;
+ for (Iterator it = list.iterator(); it.hasNext(); i++) {
+ Object key = it.next();
+ Object value = map.get(key);
+ if (i > 0) {
+ sb.append(", ");
+ }
+ inspect(key, sb, done);
+ sb.append("=>");
+ inspect(value, sb, done);
+ }
+ sb.append('}');
+ }
+
+ private static void inspect(List list, StringBuffer sb, Map done) {
+ sb.append('[');
+ int i = 0;
+ for (Iterator it = list.iterator(); it.hasNext(); i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ Object item = it.next();
+ inspect(item, sb, null);
+ }
+ sb.append(']');
+ }
+
+ private static void inspect(String str, StringBuffer sb, Map done) {
+ sb.append('"');
+ for (int i = 0; i < str.length(); i++) {
+ char ch = str.charAt(i);
+ switch (ch) {
+ case '"': sb.append("\\\""); break;
+ case '\n': sb.append("\\n"); break;
+ case '\r': sb.append("\\r"); break;
+ case '\t': sb.append("\\t"); break;
+ default: sb.append(ch); break;
+ }
+ }
+ sb.append('"');
+ }
+
+
+
+ /**
+ *
+ */
+ protected static HashMap __patterns = new HashMap();
+
+ /**
+ * match pattern and return Mather object.
+ *
+ * ex.
+ * <pre>
+ * String target = " name = foo\n mail = foo@mail.com\m";
+ * Matcher m = Util.matcher(target, "^\\s*(\\w+)\\s*=\\s*(.*)$");
+ * while (m.find()) {
+ * String key = m.group(1);
+ * String value = m.gropu(2);
+ * }
+ * </pre>
+ */
+ public static Matcher matcher(String target, String regexp) {
+ Pattern pat = (Pattern)__patterns.get(regexp);
+ if (pat == null) {
+ pat = Pattern.compile(regexp);
+ __patterns.put(regexp, pat);
+ }
+ return pat.matcher(target);
+ }
+
+
+ public static Matcher matcher(String target, Pattern regexp) {
+ return regexp.matcher(target);
+ }
+
+
+ /**
+ * return if pattern matched or not.
+ *
+ * ex.
+ * <pre>
+ * String target = " name = foo\n";
+ * if (Util.matches(target, "^\\s*(\\w+)\\s*=\\s*(.*)$")) {
+ * System.out.println("matched.");
+ * }
+ * </pre>
+ */
+ public static boolean matches(String target, String regexp) {
+ Matcher m = matcher(target, regexp);
+ return m.find();
+ }
+
+
+ public static boolean matches(String target, Pattern regexp) {
+ Matcher m = regexp.matcher(target);
+ return m.find();
+ }
+
+
+ /**
+ * shift array and return new array shifted
+ */
+ public static String[] arrayShift(String[] array) {
+ String[] new_array = new String[array.length - 1];
+ for (int i = 0; i < new_array.length; i++) {
+ new_array[i] = array[i + 1];
+ }
+ return new_array;
+ }
+
+
+ /**
+ * pop up array an dreturn new array popped
+ */
+ public static String[] arrayPop(String[] array) {
+ String[] new_array = new String[array.length - 1];
+ for (int i = 0; i < new_array.length; i++) {
+ new_array[i] = array[i];
+ }
+ return new_array;
+ }
+
+
+ /**
+ * concatenate all elements of array with separator
+ */
+ public static String join(Object[] array, String separator) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ sb.append(separator);
+ }
+ sb.append(array[i]);
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * concatenate all elements of list with separator
+ */
+ public static String join(List list, String separator) {
+ StringBuffer sb = new StringBuffer();
+ int i = 0;
+ for (Iterator it = list.iterator(); it.hasNext(); i++) {
+ Object item = it.next();
+ if (i > 0) {
+ sb.append(separator);
+ }
+ sb.append(item);
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * split string into list of line
+ */
+ public static List toListOfLines(String str) {
+ List list = new ArrayList();
+ int len = str.length();
+ int head = 0;
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+ if (ch == '\n') {
+ int tail = i + 1;
+ String line = str.substring(head, tail);
+ list.add(line);
+ head = tail;
+ }
+ }
+ if (head != len) {
+ String line = str.substring(head, len);
+ list.add(line);
+ }
+ return list;
+ }
+
+
+ /**
+ * split string into array of line
+ */
+ public static String[] toLines(String str) {
+ List list = toListOfLines(str);
+ String[] lines = new String[list.size()];
+ list.toArray(lines);
+ return lines;
+ }
+
+
+ /**
+ * return object id
+ */
+ public static Integer getId(Object obj) {
+ int id = System.identityHashCode(obj);
+ return new Integer(id);
+ }
+
+
+ /**
+ * return true if 'instance' is an instance of 'klass'
+ */
+ public static boolean isInstanceOf(Object instance, Class klass) {
+ if (instance == null || klass == null) {
+ return false;
+ }
+ Class c = instance.getClass();
+ if (klass.isInterface()) {
+ while (c != null) {
+ Class[] interfaces = c.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (interfaces[i] == klass) {
+ return true;
+ }
+ }
+ c = c.getSuperclass();
+ }
+ } else {
+ while (c != null) {
+ if (c == klass) {
+ return true;
+ }
+ c = c.getSuperclass();
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * read file content with default encoding of system
+ */
+ public static String readFile(String filename) throws IOException {
+ String charset = System.getProperty("file.encoding");
+ return readFile(filename, charset);
+ }
+
+
+ /**
+ * read file content with specified encoding
+ */
+ public static String readFile(String filename, String encoding) throws IOException {
+ InputStream stream = null;
+ String content = null;
+ try {
+ stream = new FileInputStream(filename);
+ content = readInputStream(stream, encoding);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException ignore) {}
+ }
+ }
+ return content;
+ }
+
+ /**
+ *
+ */
+ public static String readInputStream(InputStream stream) throws IOException {
+ String encoding = System.getProperty("file.encoding");
+ return readInputStream(stream, encoding);
+ }
+
+
+ /**
+ *
+ */
+ public static String readInputStream(InputStream stream, String encoding) throws IOException {
+ Reader reader = null;
+ String content = null;
+ try {
+ reader = new InputStreamReader(stream, encoding);
+ StringBuffer sb = new StringBuffer();
+ int ch;
+ while ((ch = reader.read()) >= 0) {
+ sb.append((char)ch);
+ }
+ content = sb.toString();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ignore) {}
+ }
+ }
+ return content;
+ }
+
+
+ /**
+ *
+ */
+ public static void writeFile(String filename, String content) throws IOException {
+ Writer writer = null;
+ try {
+ writer = new FileWriter(filename);
+ writer.write(content);
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
+
+ public static void makeDir(String path) throws IOException {
+ File dir = new File(path);
+ dir.mkdir();
+ }
+
+
+ public static void renameFile(String old_path, String new_path) throws IOException {
+ File old_file = new File(old_path);
+ File new_file = new File(new_path);
+ new_file.delete();
+ old_file.renameTo(new_file);
+ }
+
+
+ public static void moveFile(String filepath, String dirpath) throws IOException {
+ File old_file = new File(filepath);
+ File new_file = new File(dirpath + "/" + old_file.getName());
+ new_file.delete();
+ old_file.renameTo(new_file);
+ }
+
+
+ public static String untabify(CharSequence str) {
+ return untabify(str, 8);
+ }
+
+
+ public static String untabify(CharSequence str, int tab_width) {
+ StringBuffer sb = new StringBuffer();
+ int len = str.length();
+ int col = -1;
+ for (int i = 0; i < len; i++) {
+ col = ++col % tab_width;
+ char ch = str.charAt(i);
+ //if (ch == '\t') {
+ // int n = tab_width - col;
+ // while (--n >= 0)
+ // sb.append(' ');
+ // col = -1; // reset col
+ //} else {
+ // sb.append(ch);
+ // if (ch == '\n')
+ // col = -1; // reset col
+ //}
+ switch (ch) {
+ case '\t':
+ int n = tab_width - col;
+ while (--n >= 0) {
+ sb.append(' ');
+ }
+ col = -1; // reset col
+ break;
+ case '\n':
+ sb.append(ch);
+ col = -1; // reset col;
+ break;
+ default:
+ sb.append(ch);
+ }
+ }
+ return sb.toString();
+ }
+
+
+ private static final int VALUE_INTEGER = 1;
+ private static final int VALUE_DOUBLE = 2;
+ private static final int VALUE_STRING = 4;
+ private static final int VALUE_BOOLEAN = 8;
+ private static final int VALUE_DATE = 16;
+ private static final int VALUE_OBJECT = 32;
+
+ public static int compare(Object value1, Object value2) throws InvalidTypeException {
+ if (! (value1 instanceof Comparable)) {
+ throw new InvalidTypeException(value1.toString() + "is not Comparable.");
+ }
+ if (! (value2 instanceof Comparable)) {
+ throw new InvalidTypeException(value2.toString() + "is not Comparable.");
+ }
+ return ((Comparable)value1).compareTo((Comparable)value2);
+ }
+
+ public static int compareValues(Object value1, Object value2) throws InvalidTypeException {
+ int vtype = (valueType(value1) << 8) | valueType(value2);
+ switch (vtype) {
+ case (VALUE_INTEGER << 8) | VALUE_INTEGER :
+ return ((Integer)value1).compareTo((Integer)value2);
+ case (VALUE_DOUBLE << 8) | VALUE_DOUBLE :
+ return ((Double)value1).compareTo((Double)value2);
+ case (VALUE_STRING << 8) | VALUE_STRING :
+ return ((String)value1).compareTo((String)value2);
+ case (VALUE_BOOLEAN << 8) | VALUE_BOOLEAN :
+ //return ((Boolean)value1).compareTo((Boolean)value2); // J2SDK1.4 doesn't support Boolean#compareTo()!
+ boolean b1 = ((Boolean)value1).booleanValue();
+ boolean b2 = ((Boolean)value2).booleanValue();
+ return b1 == b2 ? 0 : (b1 ? 1 : -1);
+ //if (b1 == b2) return 0;
+ //if (b1 && !b2) return 1;
+ //if (!b1 && b2) return -1;
+ //assert false;
+ case (VALUE_DATE << 8) | VALUE_DATE :
+ return ((Date)value1).compareTo((Date)value2);
+ //
+ case (VALUE_DOUBLE << 8) | VALUE_INTEGER :
+ case (VALUE_INTEGER << 8) | VALUE_DOUBLE :
+ double d1 = ((Number)value1).doubleValue();
+ double d2 = ((Number)value2).doubleValue();
+ return d1 > d2 ? 1 : (d1 < d2 ? -1 : 0);
+ }
+ throw new InvalidTypeException("cannot compare '" + value1.getClass().getName() + "' with '" + value2.getClass().getName());
+ }
+
+ private static int valueType(Object value) {
+ if (value instanceof Integer) return VALUE_INTEGER;
+ if (value instanceof Double) return VALUE_DOUBLE;
+ if (value instanceof String) return VALUE_STRING;
+ if (value instanceof Boolean) return VALUE_BOOLEAN;
+ if (value instanceof Date) return VALUE_DATE;
+ return VALUE_OBJECT;
+ }
+
+ public static String repeatString(String str, int times) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < times; i++) {
+ sb.append(str);
+ }
+ return sb.toString();
+ }
+
+
+ public static String[] subarray(String[] array, int begin, int end) {
+ if (begin >= end) {
+ return null;
+ }
+ if (end > array.length) {
+ end = array.length;
+ }
+ int size = end - begin;
+ String[] array2 = new String[size];
+ int i, j;
+ for (i = begin, j = 0; i < end; i++, j++) {
+ array2[j] = array[i];
+ }
+ return array2;
+ }
+
+ public static String[] subarray(String[] array, int begin) {
+ if (begin < 0) {
+ begin += array.length;
+ }
+ return subarray(array, begin, array.length);
+ }
+
+
+ /**
+ * parse command-line options.
+ *
+ * ex.
+ * <pre>
+ * public static void main(String[] arg) {
+ * String singles = "hv"; // options which takes no argument.
+ * String requireds = "fI"; // options which requires an argument.
+ * String optionals = "i"; // options which can take optional argument.
+ * try {
+ * Object[] ret = parseCommandOptions(args, singles, requireds, optionals);
+ * Map options = (Map)ret[0];
+ * Map properties = (Map)ret[1];
+ * String[] filenames = (String[])ret[2];
+ * //...
+ * } catch (CommandOptionException ex) {
+ * char option = ex.getOption();
+ * String error_symbol = ex.getErrorSymbol();
+ * Systen.err.println("*** error: " + ex.getMessage());
+ * }
+ * }
+ * </pre>
+ *
+ * @param args command-line strings
+ * @param singles options which takes no argument
+ * @param requireds options which requires an argument.
+ * @param optionals otpions which can take optional argument.
+ * @return array of options(Map), properties(Map), and filenames(String[])
+ */
+ public static Object[] parseCommandOptions(String[] args, String singles, String requireds, String optionals) throws CommandOptionException {
+ Map options = new HashMap();
+ Map properties = new HashMap();
+ String[] filenames = null;
+ //
+ int i;
+ for (i = 0; i < args.length; i++) {
+ if (args[i].length() == 0 || args[i].charAt(0) != '-') {
+ break;
+ }
+ String opt = args[i];
+ int len = opt.length();
+ if (len == 1) { // option '-' means "don't parse arguments!"
+ i++;
+ break;
+ }
+ assert len > 1;
+ if (opt.charAt(1) == '-') { // properties (--pname=pvalue)
+ String pname;
+ Object pvalue;
+ int idx = opt.indexOf('=');
+ if (idx >= 0) {
+ pname = opt.substring(2, idx);
+ pvalue = idx + 1 < opt.length() ? opt.substring(idx + 1) : "";
+ } else {
+ pname = opt.substring(2);
+ pvalue = Boolean.TRUE;
+ }
+ properties.put(pname, pvalue);
+ } else { // command-line options
+ for (int j = 1; j < len; j++) {
+ char ch = opt.charAt(j);
+ String chstr = Character.toString(ch);
+ if (singles != null && singles.indexOf(ch) >= 0) {
+ options.put(chstr, Boolean.TRUE);
+ } else if (requireds != null && requireds.indexOf(ch) >= 0) {
+ String arg = null;
+ if (++j < len) {
+ arg = opt.substring(j);
+ } else if (++i < args.length) {
+ arg = args[i];
+ } else {
+ throw new CommandOptionException("-" + ch + ": filename required.", ch, "command.option.noarg");
+ }
+ options.put(chstr, arg);
+ break;
+ } else if (optionals != null && optionals.indexOf(ch) >= 0) {
+ Object arg = null;
+ if (++j < len) {
+ arg = opt.substring(j);
+ } else {
+ arg = Boolean.TRUE;
+ }
+ options.put(chstr, arg);
+ break;
+ } else {
+ throw new CommandOptionException("-" + ch + "invalid option.", ch, "command.option.invalid");
+ }
+ }
+ }
+ }
+
+ // filenames
+ //String[] filenames = i == args.length ? new String[0] : Util.subarray(args, i);
+ assert i <= args.length;
+ int n = args.length - i;
+ filenames = new String[n];
+ for (int j = 0; i < args.length; i++, j++) {
+ filenames[j] = args[i];
+ }
+
+ //
+ return new Object[] { options, properties, filenames };
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/ValidationException.java b/javatoscachecker/kwalify/src/main/java/kwalify/ValidationException.java
new file mode 100644
index 0000000..5723e01
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/ValidationException.java
@@ -0,0 +1,26 @@
+/*
+ * @(#)ValidationException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class which represents validation error.
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ */
+public class ValidationException extends BaseException {
+ private static final long serialVersionUID = -2991121377463453973L;
+
+ public ValidationException(String message, String path, Object value, Rule rule, String error_symbol) {
+ super(message, path, value, rule, error_symbol);
+ }
+
+ public ValidationException(String message, String path) {
+ this(message, path, null, null, null);
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/Validator.java b/javatoscachecker/kwalify/src/main/java/kwalify/Validator.java
new file mode 100644
index 0000000..1b3dd53
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/Validator.java
@@ -0,0 +1,415 @@
+/*
+ * @(#)Validator.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Collections;
+
+/**
+ * validation engine
+ *
+ * ex.
+ * <pre>
+ *
+ * // load YAML document
+ * String str = Util.readFile("document.yaml");
+ * YamlParser parser = new YamlParser(str);
+ * Object document = parser.parse();
+ *
+ * // load schema
+ * Object schema = YamlUtil.loadFile("schema.yaml");
+ *
+ * // generate validator and validate document
+ * Validator validator = new Validator(shema);
+ * List errors = validator.validate(document);
+ *
+ * // show errors
+ * if (errors != null && errors.size() > 0) {
+ * parser.setErrorsLineNumber(errors);
+ * java.util.Collections.sort(errors);
+ * for (Iterator it = errors.iterator(); it.hasNext(); ) {
+ * ValidationError error = (ValidationError)it.next();
+ * int linenum = error.getLineNumber();
+ * String path = error.getPath();
+ * String mesg = error.getMessage();
+ * String s = "- (" + linenum + ") [" + path + "] " + mesg;
+ * System.err.println(s);
+ * }
+ * }
+ * </pre>
+ *
+ * @version $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ */
+public class Validator {
+ private Rule _rule;
+
+ public Validator(Map schema) throws SchemaException {
+ _rule = new Rule(schema);
+ }
+
+ public Validator(Object schema) throws SchemaException {
+ _rule = new Rule(schema);
+ }
+
+ public Rule getRule() { return _rule; }
+ //public void setRule(Rule rule) { _rule = rule; }
+
+ public List validate(Object value) {
+ ValidationContext vctx = new ValidationContext();
+ _validateRule(value, _rule, vctx);
+ return vctx.getErrors();
+ }
+
+ protected boolean preValidationHook(Object value, Rule rule, ValidationContext context) {
+ // nothing
+ return false;
+ }
+
+ protected void postValidationHook(Object value, Rule rule, ValidationContext context) {
+ }
+
+ private void _validateRule(Object value, Rule rule, ValidationContext context) {
+ //why is done necessary? why would one end up having to validate twice the same collection??
+ if (Types.isCollection(value)) {
+ if (context.done(value))
+ return;
+ }
+ if (rule.isRequired() && value == null) {
+ Object[] args = new Object[] { Types.typeName(rule.getType()) };
+ context.addError("required.novalue", rule, value, args);
+ return;
+ }
+
+ if (preValidationHook(value, rule, context)) {
+ /* a 'higher power says is ok */
+ postValidationHook(value, rule, context);
+ return;
+ }
+
+ //Class klass = rule.getTypeClass();
+ //if (klass != null && value != null && !klass.isInstance(value)) {
+
+ int n = context.errorCount();
+ validateRule(value, rule, context);
+ if (context.errorCount() != n) {
+ return;
+ }
+ //
+ postValidationHook(value, rule, context);
+ }
+
+ /* this is the default validation process */
+ protected void validateRule(Object value, Rule rule, ValidationContext context) {
+
+ if (value != null && ! Types.isCorrectType(value, rule.getType())) {
+ Object[] args = new Object[] { Types.typeName(rule.getType()) };
+ context.addError("type.unmatch", rule, value, args);
+ return;
+ }
+ //
+ if (rule.getSequence() != null) {
+ assert value == null || value instanceof List;
+ validateSequence((List)value, rule, context);
+ } else if (rule.getMapping() != null) {
+ assert value == null || value instanceof Map;
+ validateMapping((Map)value, rule, context);
+ } else if (rule.getReference() != null) {
+ validateReference(value, rule, context);
+ } else {
+ validateScalar(value, rule, context);
+ }
+ }
+
+ private void validateScalar(Object value, Rule rule, ValidationContext context) {
+ assert rule.getSequence() == null;
+ assert rule.getMapping() == null;
+ if (rule.getAssert() != null) {
+ //boolean result = evaluate(rule.getAssert());
+ //if (! result) {
+ // errors.add("asset.failed", rule, path, value, new Object[] { rule.getAssert() });
+ //}
+ }
+ if (rule.getEnum() != null) {
+ if (! rule.getEnum().contains(value)) {
+ //if (Util.matches(keyname, "\\A\\d+\\z") keyname = "enum";
+ context.addError("enum.notexist", rule, value, new Object[] { context.getPathElement() });
+ }
+ }
+ //
+ if (value == null) {
+ return;
+ }
+ //
+ if (rule.getPattern() != null) {
+ if (! Util.matches(value.toString(), rule.getPatternRegexp())) {
+ context.addError("pattern.unmatch", rule, value, new Object[] { rule.getPattern() });
+ }
+ }
+ if (rule.getRange() != null) {
+ assert Types.isScalar(value);
+ Map range = rule.getRange();
+ Object v;
+ if ((v = range.get("max")) != null && Util.compareValues(v, value) < 0) {
+ context.addError("range.toolarge", rule, value, new Object[] { v.toString() });
+ }
+ if ((v = range.get("min")) != null && Util.compareValues(v, value) > 0) {
+ context.addError("range.toosmall", rule, value, new Object[] { v.toString() });
+ }
+ if ((v = range.get("max-ex")) != null && Util.compareValues(v, value) <= 0) {
+ context.addError("range.toolargeex", rule, value, new Object[] { v.toString() });
+ }
+ if ((v = range.get("min-ex")) != null && Util.compareValues(v, value) >= 0) {
+ context.addError("range.toosmallex", rule, value, new Object[] { v.toString() });
+ }
+ }
+ if (rule.getLength() != null) {
+ assert value instanceof String;
+ Map length = rule.getLength();
+ int len = value.toString().length();
+ Integer v;
+ if ((v = (Integer)length.get("max")) != null && v.intValue() < len) {
+ context.addError("length.toolong", rule, value, new Object[] { new Integer(len), v });
+ }
+ if ((v = (Integer)length.get("min")) != null && v.intValue() > len) {
+ context.addError("length.tooshort", rule, value, new Object[] { new Integer(len), v });
+ }
+ if ((v = (Integer)length.get("max-ex")) != null && v.intValue() <= len) {
+ context.addError("length.toolongex", rule, value, new Object[] { new Integer(len), v });
+ }
+ if ((v = (Integer)length.get("min-ex")) != null && v.intValue() >= len) {
+ context.addError("length.tooshortex", rule, value, new Object[] { new Integer(len), v });
+ }
+ }
+ }
+
+
+ private void validateSequence(List sequence, Rule seq_rule, ValidationContext context) {
+ assert seq_rule.getSequence() instanceof List;
+ assert seq_rule.getSequence().size() == 1;
+ if (sequence == null) {
+ return;
+ }
+ Rule rule = (Rule)seq_rule.getSequence().get(0);
+ int i = 0;
+ for (Iterator it = sequence.iterator(); it.hasNext(); i++) {
+ Object val = it.next();
+ context.addPathElement(String.valueOf(i));
+ _validateRule(val, rule, context); // validate recursively
+ context.removePathElement();
+ }
+ if (rule.getType().equals("map")) {
+ Map mapping = rule.getMapping();
+ List unique_keys = new ArrayList();
+ for (Iterator it = mapping.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Rule map_rule = (Rule)mapping.get(key);
+ if (map_rule.isUnique() || map_rule.isIdent()) {
+ unique_keys.add(key);
+ }
+ }
+ //
+ if (unique_keys.size() > 0) {
+ for (Iterator it = unique_keys.iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Map table = new HashMap(); // val => index
+ int j = 0;
+ for (Iterator it2 = sequence.iterator(); it2.hasNext(); j++) {
+ Map map = (Map)it2.next();
+ Object val = map.get(key);
+ if (val == null) {
+ continue;
+ }
+ if (table.containsKey(val)) {
+ String path = context.getPath();
+ String prev_path = path + "/" + table.get(val) + "/" + key;
+ context.addPathElement(String.valueOf(j))
+ .addPathElement(key.toString());
+ context.addError("value.notunique", rule, val, new Object[] { prev_path });
+ context.removePathElement()
+ .removePathElement();
+ } else {
+ table.put(val, new Integer(j));
+ }
+ }
+ }
+ }
+ } else if (rule.isUnique()) {
+ Map table = new HashMap(); // val => index
+ int j = 0;
+ for (Iterator it = sequence.iterator(); it.hasNext(); j++) {
+ Object val = it.next();
+ if (val == null) {
+ continue;
+ }
+ if (table.containsKey(val)) {
+ String path = context.getPath();
+ String prev_path = path + "/" + table.get(val);
+ context.addPathElement(String.valueOf(j))
+ .addError("value.notunique", rule, val, new Object[] { prev_path })
+ .removePathElement();
+ } else {
+ table.put(val, new Integer(j));
+ }
+ }
+ }
+ }
+
+
+ private void validateMapping(Map mapping, Rule map_rule, ValidationContext context) {
+ assert map_rule.getMapping() instanceof Map;
+ if (mapping == null) {
+ return;
+ }
+ Map m = map_rule.getMapping();
+ for (Iterator it = m.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Rule rule = (Rule)m.get(key);
+ if (rule.isRequired() && !mapping.containsKey(key)) {
+ context.addError("required.nokey", rule, mapping, new Object[] { key });
+ }
+ }
+ for (Iterator it = mapping.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object val = mapping.get(key);
+ Rule rule = (Rule)m.get(key);
+ context.addPathElement(key.toString());
+ if (rule == null) {
+ context.addError("key.undefined", rule, mapping, new Object[] { key.toString() + ":", map_rule.getName() + m.keySet().toString() });
+ } else {
+ _validateRule(val, rule, context); // validate recursively
+ }
+ context.removePathElement();
+ }
+ }
+
+ private void validateReference(Object value, Rule ref_rule, ValidationContext context) {
+ //look only up the rule chain. This is a limitation
+ Rule refed = ref_rule;
+ while ((refed = refed.getParent()) != null) {
+ if (refed.getName() != null && refed.getName().equals(ref_rule.getReference())) {
+ validateRule(value, refed, context);
+ return;
+ }
+ }
+ context.addError("ref.nosuchrule", ref_rule, value, new Object[] { ref_rule.getReference() });
+ }
+
+ public class ValidationContext {
+
+ private StringBuilder path = new StringBuilder("");
+ private List errors = new LinkedList();
+ private Map done = new IdentityHashMap(); //completion tracker
+
+ private ValidationContext() {
+ }
+
+ public String getPath() {
+ return this.path.toString();
+ }
+
+ public Validator getValidator() {
+ return Validator.this;
+ }
+
+ public ValidationContext addPathElement(String theElement) {
+ this.path.append("/")
+ .append(theElement);
+ return this;
+ }
+
+ public String getPathElement() {
+ int index = this.path.lastIndexOf("/");
+ return index >= 0 ? this.path.substring(index + 1) : this.path.toString();
+ }
+
+ public ValidationContext removePathElement() {
+ int index = this.path.lastIndexOf("/");
+ if (index >= 0)
+ this.path.delete(index, this.path.length());
+ return this;
+ }
+
+ protected ValidationContext addError(String error_symbol, Rule rule, Object value, Object[] args) {
+ addError(
+ new ValidationException(
+ Messages.buildMessage(error_symbol, value, args), getPath(), value, rule, error_symbol));
+ return this;
+ }
+
+ protected ValidationContext addError(String error_symbol, Rule rule, String relpath, Object value, Object[] args) {
+ addError(
+ new ValidationException(
+ Messages.buildMessage(error_symbol, value, args), getPath()+"/"+relpath, value, rule, error_symbol));
+ return this;
+ }
+
+ public ValidationContext addError(String message, Rule rule, Object value, Throwable cause) {
+ addError(
+ new ValidationException(
+ message + ((cause == null) ? "" : ", cause " + cause), getPath(), value, rule, ""));
+ return this;
+ }
+
+ public ValidationContext addError(ValidationException theError) {
+ this.errors.add(theError);
+ return this;
+ }
+
+
+ public List getErrors() {
+ return Collections.unmodifiableList(this.errors);
+ }
+
+ public boolean hasErrors() {
+ return this.errors.isEmpty();
+ }
+
+ public int errorCount() {
+ return this.errors.size();
+ }
+
+ private boolean done(Object theTarget) {
+ if (this.done.get(theTarget) != null) {
+ return true;
+ }
+ this.done.put(theTarget, Boolean.TRUE);
+ return false;
+ }
+
+ private boolean isDone(Object theTarget) {
+ return this.done.get(theTarget) != null;
+ }
+ }
+
+/*
+ public static void main(String[] args) throws Exception {
+ Map schema = (Map)YamlUtil.loadFile("schema.yaml");
+ Validator validator = new Validator(schema);
+ String filename = args.length > 0 ? args[0] : "document.yaml";
+ Object document = YamlUtil.loadFile(filename);
+ List errors = validator.validate(document);
+ if (errors != null && errors.size() > 0) {
+ for (Iterator it = errors.iterator(); it.hasNext(); ) {
+ ValidationException error = (ValidationException)it.next();
+ //String s = "- [" + error.getPath() + "] " + error.getMessage();
+ String s = "- <" + error.getErrorSymbol() + ">[" + error.getPath() + "] " + error.getMessage();
+ System.out.println(s);
+ }
+ } else {
+ System.out.println("validtion OK.");
+ }
+ }
+*/
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/YamlParser.java b/javatoscachecker/kwalify/src/main/java/kwalify/YamlParser.java
new file mode 100644
index 0000000..fbe351c
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/YamlParser.java
@@ -0,0 +1,156 @@
+/*
+ * @(#)YamlParser.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+package kwalify;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * yaml parser which can keep line number of path.
+ *
+ * ex.
+ * <pre>
+ * String yaml_str = Util.readFile("document.yaml");
+ * YamlParser parser = new YamlParser(yaml_str);
+ * Object document = parser.parse();
+ * </pre>
+ */
+public class YamlParser extends PlainYamlParser {
+ private Map _linenums_table = new IdentityHashMap(); // object => sequence or mapping
+ private int _first_linenum = -1;
+ private Object _document = null;
+
+ public YamlParser(String yaml_str) {
+ super(yaml_str);
+ }
+
+ public Object parse() throws SyntaxException {
+ _document = super.parse();
+ return _document;
+ }
+
+ protected String getLine() {
+ String line = super.getLine();
+ if (_first_linenum < 0) {
+ _first_linenum = currentLineNumber();
+ }
+ return line;
+ }
+
+
+ public int getPathLineNumber(String ypath) throws InvalidPathException {
+ if (_document == null) {
+ return -1;
+ }
+ if (ypath.length() == 0 || ypath.equals("/")) {
+ return 1;
+ }
+ String[] elems = ypath.split("/");
+ String last_elem = elems.length > 0 ? elems[elems.length - 1] : null;
+ int i = ypath.charAt(0) == '/' ? 1 : 0;
+ int len = elems.length - 1;
+ Object c = _document; // collection
+ for ( /* nothing */ ; i < len; i++) {
+ if (c == null) {
+ throw new InvalidPathException(ypath);
+ } else if (c instanceof Map) {
+ c = ((Map)c).get(elems[i]);
+ } else if (c instanceof List) {
+ int index = Integer.parseInt(elems[i]);
+ if (index < 0 || ((List)c).size() < index) {
+ throw new InvalidPathException(ypath);
+ }
+ c = ((List)c).get(index);
+ } else {
+ throw new InvalidPathException(ypath);
+ }
+ }
+
+ if (c == null) {
+ throw new InvalidPathException(ypath);
+ }
+ Object linenums = _linenums_table.get(c); // Map or List
+ int linenum = -1;
+ if (c instanceof Map) {
+ assert linenums instanceof Map;
+ Object d = ((Map)linenums).get(last_elem);
+ linenum = ((Integer)d).intValue();
+ } else if (c instanceof List) {
+ assert linenums instanceof List;
+ int index = Integer.parseInt(last_elem);
+ if (index < 0 || ((List)linenums).size() <= index) {
+ throw new InvalidPathException(ypath);
+ }
+ Object d = ((List)linenums).get(index);
+ linenum = ((Integer)d).intValue();
+ } else {
+ throw new InvalidPathException(ypath);
+ }
+ return linenum;
+ }
+
+ public void setErrorsLineNumber(List errors) throws InvalidPathException {
+ for (Iterator it = errors.iterator(); it.hasNext(); ) {
+ ValidationException ex = (ValidationException)it.next();
+ ex.setLineNumber(getPathLineNumber(ex.getPath()));
+ }
+ }
+
+ protected List createSequence(int linenum) {
+ List seq = new ArrayList();
+ _linenums_table.put(seq, new ArrayList());
+ return seq;
+ }
+
+ protected void addSequenceValue(List seq, Object value, int linenum) {
+ seq.add(value);
+ List linenums = (List)_linenums_table.get(seq);
+ linenums.add(new Integer(linenum));
+ }
+
+ protected void setSequenceValueAt(List seq, int index, Object value, int linenum) {
+ seq.set(index, value);
+ List linenums = (List)_linenums_table.get(seq);
+ linenums.set(index, new Integer(linenum));
+ }
+
+ protected Map createMapping(int linenum) {
+ Map map = super.createMapping(linenum);
+ _linenums_table.put(map, new HashMap());
+ return map;
+ }
+
+ protected void setMappingValueWith(Map map, Object key, Object value, int linenum) {
+ map.put(key, value);
+ Map linenums = (Map)_linenums_table.get(map);
+ assert linenums != null;
+ linenums.put(key, new Integer(linenum));
+ }
+
+ protected void setMappingDefault(Map map, Object value, int linenum) {
+ super.setMappingDefault(map, value, linenum);
+ Map linenums = (Map)_linenums_table.get(map);
+ linenums.put(new Character('='), new Integer(linenum));
+ }
+
+ protected void mergeMapping(Map map, Map map2, int linenum) {
+ Map linenums = (Map)_linenums_table.get(map);
+ Map linenums2 = (Map)_linenums_table.get(map2);
+ assert linenums2 != null;
+ for (Iterator it = map2.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ if (! map.containsKey(key)) {
+ map.put(key, map2.get(key));
+ linenums.put(key, linenums2.get(key));
+ }
+ }
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/YamlSyntaxException.java b/javatoscachecker/kwalify/src/main/java/kwalify/YamlSyntaxException.java
new file mode 100644
index 0000000..a8b1011
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/YamlSyntaxException.java
@@ -0,0 +1,23 @@
+/*
+ * @(#)YamlSyntaxException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown by YamlParser when syntax of YAML document is wrong
+ *
+ * @revision $Rev: 4 $
+ * @release $Release: 0.5.1 $
+ * @see SyntaxException
+ */
+public class YamlSyntaxException extends SyntaxException {
+ private static final long serialVersionUID = 2951669148531823857L;
+
+ public YamlSyntaxException(String message, int linenum) {
+ super(message, linenum);
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/YamlUtil.java b/javatoscachecker/kwalify/src/main/java/kwalify/YamlUtil.java
new file mode 100644
index 0000000..90dc17c
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/YamlUtil.java
@@ -0,0 +1,62 @@
+/*
+ * @(#)YamlUtil.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.Reader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+/**
+ * utilify class for yaml.
+ *
+ * @version $Rev: 3 $
+ * @release $Release: 0.5.1 $
+ */
+public class YamlUtil {
+
+ public static Object load(String yaml_str) throws SyntaxException {
+ PlainYamlParser parser = new PlainYamlParser(yaml_str);
+ Object doc = parser.parse();
+ return doc;
+ }
+
+ public static Object loadFile(String filename, String charset) throws IOException, SyntaxException {
+ Object doc = null;
+ InputStream input = null;
+ Reader reader = null;
+ try {
+ input = new FileInputStream(filename);
+ reader = new InputStreamReader(input, charset);
+ StringBuffer sb = new StringBuffer();
+ int ch;
+ while ((ch = reader.read()) >= 0) {
+ sb.append((char)ch);
+ }
+ doc = load(sb.toString());
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (Exception ignore) {}
+ }
+ if (input != null) {
+ try {
+ input.close();
+ } catch (Exception ignore) {}
+ }
+ }
+ return doc;
+ }
+
+ public static Object loadFile(String filename) throws IOException, SyntaxException {
+ String encoding = System.getProperty("file.encoding");
+ return loadFile(filename, encoding);
+ }
+
+}
diff --git a/javatoscachecker/kwalify/src/main/java/kwalify/messages.properties b/javatoscachecker/kwalify/src/main/java/kwalify/messages.properties
new file mode 100644
index 0000000..c4b45c0
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/java/kwalify/messages.properties
@@ -0,0 +1,110 @@
+command.help = \
+ Usage1: %s [-hvstlE] -f schema.yaml doc.yaml [doc2.yaml ...]\n\
+ Usage2: %s [-hvstlE] -m schema.yaml [schema2.yaml ...]\n\
+ \ \ -h, --help : help\n\
+ \ \ -v : version\n\
+ \ \ -s : silent\n\
+ \ \ -f schema.yaml : schema definition file\n\
+ \ \ -m : meta-validation mode\n\
+ \ \ -t : expand tab character automatically\n\
+ \ \ -l : show linenumber when errored (experimental)\n\
+ \ \ -E : show errors in emacs-style (implies '-l')\n
+command.option.noaction = command-line option '-f' or '-m' required.
+meta.empty = %s: empty.
+meta.valid = %s: ok.
+meta.invalid = %s: NG!
+schema.empty = %s#%d: empty.
+validation.empty = %s#%d: empty.
+validation.valid = %s#%d: valid.
+validation.invalid = %s#%d: INVALID
+command.property.invalid = %s: invalid property.
+command.option.noarg = -%s: argument required.
+command.option.noschema = -%s: schema filename required.
+command.option.invalid = -%s: invalid command option.
+schema.notmap = schema definition is not a mapping.
+key.unknown = unknown key.
+type.notstr = not a string.
+type.unknown = unknown type.
+required.notbool = not a boolean.
+pattern.notstr = not a string (or regexp)
+pattern.notmatch = should be '/..../'.
+pattern.syntaxerr = has regexp error.
+enum.notseq = not a sequence.
+enum.notscalar = not available with seq or map.
+enum.type.unmatch = %s type expected.
+enum.duplicate = duplicated enum value.
+assert.notstr = not a string.
+assert.noval = 'val' is not used.
+assert.syntaxerr = expression syntax error.
+range.notmap = not a mapping.
+range.notscalar = is available only with scalar type.
+range.notcollection = not a collection type.
+range.type.unmatch = not a %s.
+range.undefined = undefined key.
+range.twomax = both 'max' and 'max-ex' are not available at once.
+range.twomin = both 'min' and 'min-ex' are not available at once.
+range.maxltmin = max '%s' is less than min '%s'.
+range.maxleminex = max '%s' is less than or equal to min-ex '%s'.
+range.maxexlemin = max-ex '%s' is less than or equal to min '%s'.
+range.maxexleminex = max-ex '%s' is less than or equal to min-ex '%s'.
+length.notmap = not a mapping.
+length.nottext = is available only with string or text.
+length.notint = not an integer.
+length.undefined = undefined key.
+length.twomax = both 'max' and 'max-ex' are not available at once.
+length.twomin = both 'min' and 'min-ex' are not available at once.
+length.maxltmin = max '%s' is less than min '%s'.
+length.maxleminex = max '%s' is less than or equal to min-ex '%s'.
+length.maxexlemin = max-ex '%s' is less than or equal to min '%s'.
+length.maxexleminex = max-ex '%s' is less than or equal to min-ex '%s'.
+ident.notbool = not a boolean.
+ident.notscalar = is available only with a scalar type.
+ident.onroot = is not available on root element.
+ident.notmap = is available only with an element of mapping.
+unique.notbool = not a boolean.
+unique.notscalar = is available only with a scalar type.
+unique.onroot = is not available on root element.
+sequence.notseq = not a sequence.
+sequence.noelem = required one element.
+sequence.toomany = required just one element.
+mapping.notmap = not a mapping.
+mapping.noelem = required at least one element.
+seq.nosequence = type 'seq' requires 'sequence:'.
+seq.conflict = not available with sequence.
+map.nomapping = type 'map' requires 'mapping:'.
+map.conflict = not available with mapping.
+scalar.conflict = not available with scalar type.
+enum.conflict = not available with 'enum:'.
+required.novalue = value required but none.
+type.unmatch = not a %s.
+assert.failed = assertion expression failed (%s).
+enum.notexist = invalid %s value.
+pattern.unmatch = not matched to pattern %s.
+range.toolarge = too large (> max %s).
+range.toosmall = too small (< min %s).
+range.toolargeex = too large (>= max %s).
+range.toosmallex = too small (<= min %s).
+length.toolong = too long (length %d > max %d).
+length.tooshort = too short (length %d < min %d).
+length.toolongex = too long (length %d >= max %d).
+length.tooshortex = too short (length %d <= min %d).
+value.notunique = is already used at '%s'.
+required.nokey = key '%s:' is required.
+key.undefined = key '%s' is undefined. Expecting one of %s.
+flow.hastail = flow style sequence is closed but got '%s'.
+flow.eof = found EOF when parsing flow style.
+flow.noseqitem = sequence item required (or last comma is extra).
+flow.seqnotclosed = flow style sequence requires ']'.
+flow.mapnoitem = mapping item required (or last comma is extra).
+flow.mapnotclosed = flow style mapping requires '}'.
+flow.nocolon = ':' expected but got '%s'.
+anchor.duplicated = anchor '%s' is already used.
+alias.extradata = alias cannot take any data.
+anchor.notfound = anchor '%s' not found
+sequence.noitem = sequence item is expected.
+sequence.badindent = illegal indent of sequence.
+mapping.noitem = mapping item is expected.
+mapping.badindent = illegal indent of mapping.
+collection.notcollection = not a collection
+ref.nosuchrule = no rule '%s' in scope
+
diff --git a/javatoscachecker/kwalify/src/main/resources/kwalify/messages.properties b/javatoscachecker/kwalify/src/main/resources/kwalify/messages.properties
new file mode 100644
index 0000000..c4b45c0
--- /dev/null
+++ b/javatoscachecker/kwalify/src/main/resources/kwalify/messages.properties
@@ -0,0 +1,110 @@
+command.help = \
+ Usage1: %s [-hvstlE] -f schema.yaml doc.yaml [doc2.yaml ...]\n\
+ Usage2: %s [-hvstlE] -m schema.yaml [schema2.yaml ...]\n\
+ \ \ -h, --help : help\n\
+ \ \ -v : version\n\
+ \ \ -s : silent\n\
+ \ \ -f schema.yaml : schema definition file\n\
+ \ \ -m : meta-validation mode\n\
+ \ \ -t : expand tab character automatically\n\
+ \ \ -l : show linenumber when errored (experimental)\n\
+ \ \ -E : show errors in emacs-style (implies '-l')\n
+command.option.noaction = command-line option '-f' or '-m' required.
+meta.empty = %s: empty.
+meta.valid = %s: ok.
+meta.invalid = %s: NG!
+schema.empty = %s#%d: empty.
+validation.empty = %s#%d: empty.
+validation.valid = %s#%d: valid.
+validation.invalid = %s#%d: INVALID
+command.property.invalid = %s: invalid property.
+command.option.noarg = -%s: argument required.
+command.option.noschema = -%s: schema filename required.
+command.option.invalid = -%s: invalid command option.
+schema.notmap = schema definition is not a mapping.
+key.unknown = unknown key.
+type.notstr = not a string.
+type.unknown = unknown type.
+required.notbool = not a boolean.
+pattern.notstr = not a string (or regexp)
+pattern.notmatch = should be '/..../'.
+pattern.syntaxerr = has regexp error.
+enum.notseq = not a sequence.
+enum.notscalar = not available with seq or map.
+enum.type.unmatch = %s type expected.
+enum.duplicate = duplicated enum value.
+assert.notstr = not a string.
+assert.noval = 'val' is not used.
+assert.syntaxerr = expression syntax error.
+range.notmap = not a mapping.
+range.notscalar = is available only with scalar type.
+range.notcollection = not a collection type.
+range.type.unmatch = not a %s.
+range.undefined = undefined key.
+range.twomax = both 'max' and 'max-ex' are not available at once.
+range.twomin = both 'min' and 'min-ex' are not available at once.
+range.maxltmin = max '%s' is less than min '%s'.
+range.maxleminex = max '%s' is less than or equal to min-ex '%s'.
+range.maxexlemin = max-ex '%s' is less than or equal to min '%s'.
+range.maxexleminex = max-ex '%s' is less than or equal to min-ex '%s'.
+length.notmap = not a mapping.
+length.nottext = is available only with string or text.
+length.notint = not an integer.
+length.undefined = undefined key.
+length.twomax = both 'max' and 'max-ex' are not available at once.
+length.twomin = both 'min' and 'min-ex' are not available at once.
+length.maxltmin = max '%s' is less than min '%s'.
+length.maxleminex = max '%s' is less than or equal to min-ex '%s'.
+length.maxexlemin = max-ex '%s' is less than or equal to min '%s'.
+length.maxexleminex = max-ex '%s' is less than or equal to min-ex '%s'.
+ident.notbool = not a boolean.
+ident.notscalar = is available only with a scalar type.
+ident.onroot = is not available on root element.
+ident.notmap = is available only with an element of mapping.
+unique.notbool = not a boolean.
+unique.notscalar = is available only with a scalar type.
+unique.onroot = is not available on root element.
+sequence.notseq = not a sequence.
+sequence.noelem = required one element.
+sequence.toomany = required just one element.
+mapping.notmap = not a mapping.
+mapping.noelem = required at least one element.
+seq.nosequence = type 'seq' requires 'sequence:'.
+seq.conflict = not available with sequence.
+map.nomapping = type 'map' requires 'mapping:'.
+map.conflict = not available with mapping.
+scalar.conflict = not available with scalar type.
+enum.conflict = not available with 'enum:'.
+required.novalue = value required but none.
+type.unmatch = not a %s.
+assert.failed = assertion expression failed (%s).
+enum.notexist = invalid %s value.
+pattern.unmatch = not matched to pattern %s.
+range.toolarge = too large (> max %s).
+range.toosmall = too small (< min %s).
+range.toolargeex = too large (>= max %s).
+range.toosmallex = too small (<= min %s).
+length.toolong = too long (length %d > max %d).
+length.tooshort = too short (length %d < min %d).
+length.toolongex = too long (length %d >= max %d).
+length.tooshortex = too short (length %d <= min %d).
+value.notunique = is already used at '%s'.
+required.nokey = key '%s:' is required.
+key.undefined = key '%s' is undefined. Expecting one of %s.
+flow.hastail = flow style sequence is closed but got '%s'.
+flow.eof = found EOF when parsing flow style.
+flow.noseqitem = sequence item required (or last comma is extra).
+flow.seqnotclosed = flow style sequence requires ']'.
+flow.mapnoitem = mapping item required (or last comma is extra).
+flow.mapnotclosed = flow style mapping requires '}'.
+flow.nocolon = ':' expected but got '%s'.
+anchor.duplicated = anchor '%s' is already used.
+alias.extradata = alias cannot take any data.
+anchor.notfound = anchor '%s' not found
+sequence.noitem = sequence item is expected.
+sequence.badindent = illegal indent of sequence.
+mapping.noitem = mapping item is expected.
+mapping.badindent = illegal indent of mapping.
+collection.notcollection = not a collection
+ref.nosuchrule = no rule '%s' in scope
+