summaryrefslogtreecommitdiffstats
path: root/dcaedt_validator/kwalify/src/main
diff options
context:
space:
mode:
authorStone, Avi (as206k) <as206k@att.com>2018-04-12 15:46:31 +0300
committerStone, Avi (as206k) <as206k@att.com>2018-04-12 15:49:38 +0300
commit5032434b101f25fa44d2e1f8dc8393e30af1ed4f (patch)
tree2dc7d37a8048e025c7412af080640da4c9a22b65 /dcaedt_validator/kwalify/src/main
parent2205633792f95f46a02bbf8f87f0c2637265d924 (diff)
DCAE-D be initial commit
DCAE-D be initial commit Issue-ID: SDC-1218 Change-Id: Id18ba96c499e785aa9ac395fbaf32d57f08c281b Signed-off-by: Stone, Avi (as206k) <as206k@att.com>
Diffstat (limited to 'dcaedt_validator/kwalify/src/main')
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/BaseException.java32
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/CommandOptionException.java33
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Defaultable.java13
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/DefaultableHashMap.java31
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/InvalidPathException.java23
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/InvalidTypeException.java21
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/KwalifyException.java20
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java19
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Main.java311
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Messages.java51
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/MetaValidator.java445
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Parser.java19
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java742
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Rule.java750
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/SchemaException.java17
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/SyntaxException.java28
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Types.java105
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Util.java456
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/ValidationException.java15
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/Validator.java382
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/YamlParser.java101
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/YamlSyntaxException.java23
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/YamlUtil.java20
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/messages.properties108
-rw-r--r--dcaedt_validator/kwalify/src/main/resources/kwalify/messages.properties107
25 files changed, 3872 insertions, 0 deletions
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/BaseException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/BaseException.java
new file mode 100644
index 0000000..a578ba4
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/BaseException.java
@@ -0,0 +1,32 @@
+/*
+ * @(#)BaseException.java $Rev: 3 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+public abstract class BaseException extends KwalifyRuntimeException {
+
+ private final String yPath;
+ private final transient Object value;
+ private final transient Rule rule;
+ private int lineNum = -1;
+
+ BaseException(String message, String ypath, Object value, Rule rule) {
+ super(message);
+ this.yPath = ypath;
+ this.value = value;
+ this.rule = rule;
+ }
+
+ public String getPath() { return "".equals(yPath) ? "/" : yPath; }
+
+ public Object getValue() { return value; }
+
+ public Rule getRule() { return rule; }
+
+ public int getLineNumber() { return lineNum; }
+
+ public void setLineNumber(int lineNum) { this.lineNum = lineNum; }
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/CommandOptionException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/CommandOptionException.java
new file mode 100644
index 0000000..e35be85
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/Defaultable.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Defaultable.java
new file mode 100644
index 0000000..f1de3fc
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/Defaultable.java
@@ -0,0 +1,13 @@
+/*
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * interface to have default value
+ */
+public interface Defaultable {
+ Object getDefault();
+ void setDefault(Object value);
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/DefaultableHashMap.java b/dcaedt_validator/kwalify/src/main/java/kwalify/DefaultableHashMap.java
new file mode 100644
index 0000000..c2c625c
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/DefaultableHashMap.java
@@ -0,0 +1,31 @@
+/*
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+/**
+ * hash map which can have default value
+ */
+public class DefaultableHashMap extends HashMap implements Defaultable {
+
+ private static final long serialVersionUID = -5224819562023897380L;
+
+ private Object defaultValue = null;
+
+ public DefaultableHashMap() {
+ super();
+ }
+
+ public Object getDefault() { return defaultValue; }
+
+ public void setDefault(Object value) { defaultValue = value; }
+
+ @Override
+ public Object get(Object key) {
+ return containsKey(key) ? super.get(key) : defaultValue;
+ }
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/InvalidPathException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/InvalidPathException.java
new file mode 100644
index 0000000..94eeca2
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/InvalidTypeException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/InvalidTypeException.java
new file mode 100644
index 0000000..fe60ca0
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/KwalifyException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/KwalifyException.java
new file mode 100644
index 0000000..976a263
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/KwalifyRuntimeException.java
new file mode 100644
index 0000000..75e4764
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/Main.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Main.java
new file mode 100644
index 0000000..d2f1881
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/Main.java
@@ -0,0 +1,311 @@
+/*
+ * @(#)Main.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import org.onap.sdc.common.onaplog.OnapLoggerDebug;
+import org.onap.sdc.common.onaplog.OnapLoggerError;
+import org.onap.sdc.common.onaplog.Enums.LogLevel;
+
+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 static OnapLoggerError errLogger = OnapLoggerError.getInstance();
+ private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
+
+ 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 character 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) {
+ debugLogger.log(LogLevel.DEBUG, Main.class.getName(), result);
+ } } catch (Exception ex) {
+ if (main != null && main.isDebug()) {
+ throw ex;
+ }
+ if ( ex instanceof CommandOptionException
+ || ex instanceof SyntaxException
+ || ex instanceof IOException) {
+ errLogger.log(LogLevel.ERROR, Main.class.getName(), "ERROR: {}", ex.getMessage());
+ status = 1;
+ }
+ }
+ System.exit(status);
+ }
+
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/Messages.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Messages.java
new file mode 100644
index 0000000..b77f04b
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/MetaValidator.java b/dcaedt_validator/kwalify/src/main/java/kwalify/MetaValidator.java
new file mode 100644
index 0000000..c8c21a7
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/MetaValidator.java
@@ -0,0 +1,445 @@
+/*
+ * @(#)MetaValidator.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import org.onap.sdc.common.onaplog.OnapLoggerDebug;
+import org.onap.sdc.common.onaplog.OnapLoggerError;
+import org.onap.sdc.common.onaplog.Enums.LogLevel;
+
+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 {
+
+ private static OnapLoggerError errLogger = OnapLoggerError.getInstance();
+ private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
+
+ 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() {
+ 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")) {
+ errLogger.log(LogLevel.ERROR, this.getClass().getName(), "*** 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);
+ }
+ }
+ }
+ }
+
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/Parser.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Parser.java
new file mode 100644
index 0000000..53c6272
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java b/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java
new file mode 100644
index 0000000..5f23a19
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java
@@ -0,0 +1,742 @@
+/*
+ * 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.regex.Matcher;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * plain yaml parser class which is a parent of YamlParser class.
+ */
+public class PlainYamlParser implements Parser {
+
+ private static final String ANCHOR = "anchor '";
+ private static final String ENDFLAG_EOF = "<EOF>";
+ private static final String ENDFLAG_DOC_BEGIN = "---";
+ private static final String ENDFLAG_DOC_END = "...";
+ private static final String REGEXP1 = "^( *)(.*)";
+ private static final String REGEXP2 = "^((?::?[-.\\w]+|'.*?'|\".*?\"|=|<<) *):(( +)(.*))?$";
+
+ public static class Alias {
+ private String label;
+ private int lineNum;
+
+ Alias(String label, int lineNum) {
+ this.label = label;
+ this.lineNum = lineNum;
+ }
+
+ String getLabel() { return label; }
+
+ int getLineNumber() { return lineNum; }
+ }
+
+
+ private String[] lines;
+ private String line = null;
+ private int linenum = 0;
+ private Map<String,Object> anchors = new HashMap<>();
+ private Map<String,Integer> aliases = new HashMap<>();
+ private String endFlag = null;
+ private String sbuf = null;
+ private int index = 0;
+
+ PlainYamlParser(String yamlStr) {
+ List list = Util.toListOfLines(yamlStr);
+ 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 && endFlag.equals(ENDFLAG_DOC_BEGIN)) {
+ data = parseChild(0);
+ }
+ if (aliases.size() > 0) {
+ resolveAliases(data);
+ }
+ return data;
+ }
+
+ public boolean hasNext() {
+ return !endFlag.equals(ENDFLAG_EOF);
+ }
+
+ private List createSequence() {
+ return new ArrayList();
+ }
+
+ private void addSequenceValue(List seq, Object value) {
+ seq.add(value);
+ }
+
+ private void setSequenceValueAt(List seq, int index, Object value) {
+ seq.set(index, value);
+ }
+
+ Map createMapping() {
+ return new DefaultableHashMap();
+ }
+
+ private void setMappingValueWith(Map map, Object key, Object value) {
+ map.put(key, value);
+ }
+
+ void setMappingDefault(Map map, Object value) {
+ if (map instanceof Defaultable) {
+ ((Defaultable)map).setDefault(value);
+ }
+ }
+
+ private void mergeMapping(Map map, Map map2) {
+ for (Object key : map2.keySet()) {
+ if (!map.containsKey(key)) {
+ Object value = map2.get(key);
+ map.put(key, value);
+ }
+ }
+ }
+
+ private void mergeList(Map map, List maplist) throws SyntaxException {
+ for (Object elem : maplist) {
+ mergeCollection(map, elem);
+ }
+ }
+
+ private void mergeCollection(Map map, Object collection) throws SyntaxException {
+ if (collection instanceof Map) {
+ mergeMapping(map, (Map)collection);
+ } else if (collection instanceof List) {
+ mergeList(map, (List)collection);
+ } else {
+ throw syntaxError("'<<' requires collection (mapping, or sequence of mapping).");
+ }
+ }
+
+ private Object createScalar(Object value) {
+ return value;
+ }
+
+ private String currentLine() {
+ return line;
+ }
+
+ int currentLineNumber() {
+ return linenum;
+ }
+
+ protected String getLine() {
+ String currentLine;
+ do {
+ currentLine = getCurrentLine();
+ } while (currentLine != null && Util.matches(currentLine, "^\\s*($|#)"));
+ return currentLine;
+ }
+
+ private String getCurrentLine() {
+ if (++linenum < lines.length) {
+ line = lines[linenum];
+ if (Util.matches(line, "^\\.\\.\\.$")) {
+ line = null;
+ endFlag = ENDFLAG_DOC_END;
+ } else if (Util.matches(line, "^---( [!%].*)?$")) {
+ line = null;
+ endFlag = ENDFLAG_DOC_BEGIN;
+ }
+ } else {
+ line = null;
+ endFlag = ENDFLAG_EOF;
+ }
+ return line;
+ }
+
+ private void resetBuffer(String str) {
+ sbuf = str.charAt(str.length() - 1) == '\n' ? str : str + "\n";
+ index = -1;
+ }
+
+ private int getCurrentCharacter() {
+ if (index + 1 < sbuf.length()) {
+ index++;
+ } else {
+ String currentLine = getLine();
+ if (currentLine == null) {
+ return -1;
+ }
+ resetBuffer(currentLine);
+ index++;
+ }
+ return sbuf.charAt(index);
+ }
+
+ private int getChar() {
+ int ch;
+ do {
+ ch = getCurrentCharacter();
+ } while (ch >= 0 && isWhite(ch));
+ return ch;
+ }
+
+ private int getCharOrNewline() {
+ int ch;
+ do {
+ ch = getCurrentCharacter();
+ } 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 currentLine = getLine();
+ if (currentLine == null) {
+ return createScalar(null);
+ }
+ Matcher m = Util.matcher(currentLine, REGEXP1);
+ 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 valueStartColumn) throws SyntaxException {
+ Object data;
+ if (Util.matches(value, "^-( |$)")) {
+ data = parseSequence(valueStartColumn, value);
+ } else if (Util.matches(value, REGEXP2)) {
+ data = parseMapping(valueStartColumn, value);
+ } else if (Util.matches(value, "^[\\[\\{]")) {
+ data = parseFlowStyle(value);
+ } else if (Util.matches(value, "^\\&[-\\w]+( |$)")) {
+ data = parseAnchor(column, value);
+ } else if (Util.matches(value, "^\\*[-\\w]+( |$)")) {
+ data = parseAlias(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(value);
+ }
+ return data;
+ }
+
+ private static boolean isWhite(int ch) {
+ return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+ }
+
+
+ private Object parseFlowStyle(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();
+ 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();
+ }
+ return data;
+ }
+
+ private List parseFlowSequence(int depth) throws SyntaxException {
+ assert currentChar() == '[';
+ List seq = createSequence();
+ int ch = getChar();
+ if (ch != '}') {
+ addSequenceValue(seq, parseFlowSequenceItem(depth + 1));
+ while ((ch = currentChar()) == ',') {
+ ch = getChar();
+ if (ch == '}') {
+ throw syntaxError("sequence item required (or last comma is extra).");
+ }
+ addSequenceValue(seq, parseFlowSequenceItem(depth + 1));
+ }
+ }
+ 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();
+ int ch = getChar();
+ if (ch != '}') {
+ Object[] pair = parseFlowMappingItem(depth + 1);
+ Object key = pair[0];
+ Object value = pair[1];
+ setMappingValueWith(map, key, value);
+ while ((ch = currentChar()) == ',') {
+ ch = getChar();
+ if (ch == '}') {
+ throw syntaxError("mapping item required (or last comman is extra.");
+ }
+ pair = parseFlowMappingItem(depth + 1);
+ key = pair[0];
+ value = pair[1];
+ setMappingValueWith(map, key, value);
+ }
+ }
+ 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 ch = currentChar();
+ Object scalar;
+ StringBuilder sb = new StringBuilder();
+ if (ch == '"' || ch == '\'') {
+ int endch = ch;
+ while ((ch = getCurrentCharacter()) >= 0 && ch != endch) {
+ sb.append((char)ch);
+ }
+ getChar();
+ scalar = sb.toString();
+ } else {
+ sb.append((char)ch);
+ while ((ch = getCurrentCharacter()) >= 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 valueStartColumn = column + 1 + tag.length() + space.length();
+ data = parseValue(column, value2, valueStartColumn);
+ } 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 valueStartColumn = column + 1 + label.length() + space.length();
+ data = parseValue(column, value2, valueStartColumn);
+ } 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(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 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) {
+ data = registerAlias(label);
+ }
+ getLine();
+ return data;
+ }
+
+ private Alias registerAlias(String label) {
+ aliases.merge(label, 1, (a, b) -> a + b);
+ return new Alias(label, linenum);
+ }
+
+
+ private void resolveAliases(Object data) throws SyntaxException {
+ 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 defaultValue = ((Defaultable)data).getDefault();
+ if (defaultValue != null) {
+ resolveAliases(defaultValue, resolved);
+ }
+ }
+ }
+
+ private void resolveAliases(List seq, Map resolved) throws SyntaxException {
+ int len = seq.size();
+ for (int i = 0; i < len; i++) {
+ Object val = seq.get(i);
+ if (val instanceof Alias) {
+ Alias alias = (Alias)val;
+ String label = alias.getLabel();
+ if (anchors.containsKey(label)) {
+ setSequenceValueAt(seq, i, anchors.get(label));
+ } 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 (Object key : map.keySet()) {
+ Object val = map.get(key);
+ if (val instanceof Alias) {
+ Alias alias = (Alias) val;
+ String label = alias.getLabel();
+ if (anchors.containsKey(label)) {
+ setMappingValueWith(map, key, anchors.get(label));
+ } 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, "^([>|])([-+]?)(\\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 currentLine;
+ StringBuilder sb = new StringBuilder();
+ int n = 0;
+ while ((currentLine = getCurrentLine()) != null) {
+ m = Util.matcher(currentLine, "^( *)(.*)$");
+ m.find();
+ String space = m.group(1);
+ String str = m.group(2);
+ if (indent < 0) {
+ indent = space.length();
+ }
+ if (str.length() == 0) {
+ 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 = currentLine.substring(indent);
+ }
+ }
+ sb.append(str);
+ if ((blockChar == '>') && (sb.charAt(sb.length() - 1) == '\n')) {
+ sb.setCharAt(sb.length() - 1, ' ');
+ }
+ }
+ if (currentLine != null && Util.matches(currentLine, "^ *#")) {
+ getLine();
+ }
+ switch (indicator) {
+ case '+':
+ handlePlus(blockChar, sb, n);
+ break;
+ case '-':
+ handleMinus(sep, sb);
+ break;
+ default:
+ if (blockChar == '>') {
+ sb.setCharAt(sb.length() - 1, '\n');
+ }
+ }
+ return createScalar(text + sb.toString());
+ }
+
+ private void handleMinus(char sep, StringBuilder sb) {
+ if (sb.charAt(sb.length() - 1) == sep) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ }
+
+ private void handlePlus(char blockChar, StringBuilder sb, int n) {
+ if (n > 0) {
+ if (blockChar == '>') {
+ sb.setCharAt(sb.length() - 1, '\n');
+ }
+ for (int i = 0; i < n; i++) {
+ sb.append('\n');
+ }
+ }
+ }
+
+
+ private List parseSequence(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^-(( +)(.*))?$");
+ List seq = createSequence();
+ 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;
+
+ Object elem;
+ if (value2 == null || value2.length() == 0) {
+ elem = parseChild(column2);
+ } else {
+ int valueStartColumn = column2 + space.length();
+ elem = parseValue(column2, value2, valueStartColumn);
+ }
+ addSequenceValue(seq, elem);
+
+ String currentLine = currentLine();
+ if (currentLine == null) {
+ break;
+ }
+ Matcher m2 = Util.matcher(currentLine, REGEXP1);
+ 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, REGEXP2);
+ Map map = createMapping();
+ while (true) {
+ Matcher m = Util.matcher(value, REGEXP2);
+ 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;
+
+ Object elem;
+ if (value2 == null || value2.length() == 0) {
+ elem = parseChild(column2);
+ } else {
+ int valueStartColumn = column2 + m.group(1).length() + m.group(3).length();
+ elem = parseValue(column2, value2, valueStartColumn);
+ }
+ if ("=".equals(v)) {
+ setMappingDefault(map, elem);
+ } else if ("<<".equals(v)) {
+ mergeCollection(map, elem);
+ } else {
+ setMappingValueWith(map, key, elem);
+ }
+
+ String currentLine = currentLine();
+ if (currentLine == null) {
+ break;
+ }
+ Matcher m2 = Util.matcher(currentLine, REGEXP1);
+ 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(String value) {
+ 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 Integer.parseInt(value, 16);
+ } else if (Util.matches(value, "^-?0\\d+$")) {
+ return Integer.parseInt(value, 8);
+ } else if (Util.matches(value, "^-?\\d+$")) {
+ return Integer.parseInt(value, 10);
+ } else if (Util.matches(value, "^-?\\d+\\.\\d+$")) {
+ return 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);
+ return cal.getTime();
+ } 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));
+
+ 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));
+ return cal.getTime();
+ } else {
+ return value;
+ }
+ }
+
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/Rule.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Rule.java
new file mode 100644
index 0000000..8dbe0b7
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/Rule.java
@@ -0,0 +1,750 @@
+/*
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.io.Serializable;
+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;
+
+import org.onap.sdc.common.onaplog.Enums.LogLevel;
+import org.onap.sdc.common.onaplog.OnapLoggerDebug;
+
+/**
+ * rule for validation.
+ * Validator class generates rule instances.
+ *
+ */
+public class Rule implements Serializable{
+ private static final String RANGE1 = "/range";
+ private static final String RANGE2 = "range:";
+ private static final String ENUM_CONFLICT = "enum.conflict";
+ private static final String MAP_CONFLICT = "map.conflict";
+ private static final String LENGTH1 = "/length";
+ private static final String LENGTH2 = "length:";
+ private static final String LENGTH3 = "/length/";
+ private static final String SEQ_CONFLICT = "seq.conflict";
+ private static final String PATTERN1 = "pattern:";
+ private static final String MAPPING1 = "mapping:";
+ private static final String SEQUENCE1 = "/sequence";
+ private static final String MAX_EX = "max-ex";
+ private static final String MIN_EX = "min-ex";
+ private static final String TYPE1 = "/type";
+ private static final String TYPE_NOTSTR = "type.notstr";
+ private static final String TYPE_UNKNOWN = "type.unknown";
+ private static final String IDENT1 = "ident:";
+ private static final String UNIQUE1 = "unique:";
+ private static final String MAPPING2 = "/mapping";
+ private static final String MAPPING3 = "/mapping/=";
+ private static final String MAPPING4 = "/mapping/";
+ private static final String SEQUENCE2 = "sequence:";
+ private static final String SCALAR_CONFLICT = "scalar.conflict";
+ private static final String UNIQUE_NOTBOOL = "unique.notbool";
+ private static final String UNIQUE_NOTSCALAR = "unique.notscalar";
+ private static final String UNIQUE_ONROOT = "unique.onroot";
+ private static final String UNIQUE2 = "/unique";
+ private static final String IDENT_ONROOT = "ident.onroot";
+ private static final String IDENT_NOTSCALAR = "ident.notscalar";
+ private static final String IDENT_NOTMAP = "ident.notmap";
+ private static final String MAP = "map";
+ private static final String EMPTY_STRING = "";
+ private static final String SLASH = "/";
+ private static final String SCHEMA_NOTMAP = "schema.notmap";
+ private static final String SCHEMA_NOTMAP1 = "schema.notmap: {}";
+ private static final String PATTERN2 = "/pattern";
+ private static final String PATTERN_NOTSTR = "pattern.notstr";
+ private static final String PATTERN_NOTMATCH = "pattern.notmatch";
+ private static final String REQUIRED_NOTBOOL = "required.notbool";
+ private static final String REQUIRED1 = "/required";
+ private static final String PATTERN_SYNTAXERR = "pattern.syntaxerr";
+ private static final String PATTERN_SYNTAX_EXCEPTION = "PatternSyntaxException: {}";
+ private static final String SEQUENCE_NOTSEQ = "sequence.notseq";
+ private static final String SEQUENCE_NOELEM = "sequence.noelem";
+ private static final String SEQUENCE_TOOMANY = "sequence.toomany";
+ private static final String SEQUENCE3 = "/sequence/";
+ private static final String MAPPING_NOTMAP = "mapping.notmap";
+ private static final String MAPPING_NOELEM = "mapping.noelem";
+ private static final String IDENT2 = "/ident";
+ private static final String IDENT_NOTBOOL = "ident.notbool";
+ private static final String LENGTH_MAXEXLEMINEX = "length.maxexleminex";
+ private static final String LENGTH_MAXEXLEMIN = "length.maxexlemin";
+ private static final String TWO_SPACES = " ";
+ private static final String NAME1 = "name: ";
+ private static final String DESC1 = "desc: ";
+ private static final String TYPE2 = "type: ";
+ private static final String REQUIRED2 = "required: ";
+ private static final String PATTERN3 = "pattern: ";
+ private static final String REGEXP = "regexp: ";
+ private static final String ASSERT1 = "assert: ";
+ private static final String IDENT3 = "ident: ";
+ private static final String UNIQUE3 = "unique: ";
+ private static final String ENUM2 = "enum:\n";
+ private static final String RANGE3 = "range: { ";
+ private static final String NAME = "name";
+ private static final String DESC = "desc";
+ private static final String SHORT = "short";
+ private static final String REQUIRED = "required";
+ private static final String TYPE = "type";
+ private static final String PATTERN = "pattern";
+ private static final String SEQUENCE = "sequence";
+ private static final String MAPPING = "mapping";
+ private static final String ASSERT = "assert";
+ private static final String RANGE = "range";
+ private static final String LENGTH = "length";
+ private static final String IDENT = "ident";
+ private static final String UNIQUE = "unique";
+ private static final String ENUM = "enum:";
+ private static final String ENUM1 = "/enum";
+ public static final String MAX = "max";
+ public static final String MIN = "min";
+
+ private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
+
+ private Rule parent;
+ private String name = null;
+ private String desc = null;
+ private String _short = null; //added by jora: only used for map types
+ private boolean required = false;
+ private String _type = null;
+ private Class typeClass = null;
+ private String pattern = null;
+ private Pattern patternRegexp = null;
+ private List enumList = null;
+ private List sequence = null;
+ private DefaultableHashMap _mapping = null;
+ private String _assert = null;
+ private Map<String,Object> range = null;
+ private Map<String,Integer> length = null;
+ private boolean ident = false;
+ private boolean unique = false;
+
+ private static final int CODE_NAME = NAME.hashCode();
+ private static final int CODE_DESC = DESC.hashCode();
+ private static final int CODE_SHORT = SHORT.hashCode();
+ 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_LENGTH = LENGTH.hashCode();
+ private static final int CODE_RANGE = RANGE.hashCode();
+ private static final int CODE_ASSERT = ASSERT.hashCode();
+ private static final int CODE_IDENT = IDENT.hashCode();
+ private static final int CODE_UNIQUE = UNIQUE.hashCode();
+ private static final int CODE_ENUM = ENUM.hashCode();
+ private static final int CODE_MAPPING = MAPPING.hashCode();
+ private static final int CODE_SEQUENCE = SEQUENCE.hashCode();
+
+ public Rule(Object schema, Rule parent) {
+ if (schema != null) {
+ if (! (schema instanceof Map)) {
+ throw schemaError(SCHEMA_NOTMAP, null, SLASH, null, null);
+ }
+ Map ruleTable = new IdentityHashMap();
+ init((Map)schema, EMPTY_STRING, ruleTable);
+ }
+ this.parent = parent;
+ }
+
+ public Rule(Object schema) {
+ this(schema, null);
+ }
+
+ public Rule(Map schema, Rule parent) {
+ if (schema != null) {
+ Map ruleTable = new IdentityHashMap();
+ init(schema, EMPTY_STRING, ruleTable);
+ }
+ this.parent = parent;
+ }
+
+ public Rule(Map schema) {
+ this(schema, null);
+ }
+
+ public Rule() {
+ this(null, null);
+ }
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+
+ public String getShort() { return _short; }
+ public void setShort(String key) { _short = key; }
+
+ public boolean isRequired() { return required; }
+ public void setRequired(boolean required) { this.required = required; }
+
+ public String getType() { return _type; }
+ public void setType(String type) { this._type = type; }
+
+ public String getPattern() { return pattern; }
+ public void setPattern(String pattern) { this.pattern = pattern; }
+
+ public Pattern getPatternRegexp() { return patternRegexp; }
+
+ public List getEnum() { return enumList; }
+ public void setEnum(List enumList) { this.enumList = enumList; }
+
+ public List getSequence() { return sequence; }
+ public void setSequence(List sequence) { this.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) { this.range = range; }
+
+ public Map getLength() { return length; }
+ public void setLength(Map length) { this.length = length; }
+
+ public boolean isIdent() { return ident; }
+
+ public boolean isUnique() { return unique; }
+ public void setUnique(boolean unique) { this.unique = unique; }
+
+ 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);
+ }
+
+ private void init(Object elem, String path, Map ruleTable) {
+ assert elem != null;
+ if (! (elem instanceof Map)) {
+ if (path == null || path.isEmpty()) {
+ path = SLASH;
+ }
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), SCHEMA_NOTMAP1, elem);
+ throw schemaError(SCHEMA_NOTMAP, null, path, null, null);
+ }
+ init((Map)elem, path, ruleTable);
+ }
+
+ private void init(Map hash, String path, Map ruleTable) {
+ Rule rule = this;
+ ruleTable.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);
+ } else if (code == CODE_DESC && key.equals(DESC)) {
+ initDescValue(value);
+ } 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, ruleTable);
+ } else if (code == CODE_MAPPING && key.equals(MAPPING)) {
+ rule = initMappingValue(value, rule, path, ruleTable);
+ }
+ }
+
+ checkConfliction(hash, rule, path);
+ }
+
+ private void initTypeValue(Object value, Rule rule, String path) {
+ if (value == null) {
+ value = Types.getDefaultType();
+ }
+ if (! (value instanceof String)) {
+ throw schemaError(TYPE_NOTSTR, rule, path + TYPE1, _type, null);
+ }
+ _type = (String)value;
+ typeClass = Types.typeClass(_type);
+ if (! Types.isBuiltinType(_type)) {
+ throw schemaError(TYPE_UNKNOWN, rule, path + TYPE1, _type, null);
+ }
+ }
+
+
+ private void initNameValue(Object value) {
+ name = value.toString();
+ }
+
+
+ private void initDescValue(Object value) {
+ desc = value.toString();
+ }
+
+ private void initShortValue(Object value, Rule rule, String path) {
+
+ //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) {
+ if (! (value instanceof Boolean)) {
+ throw schemaError(REQUIRED_NOTBOOL, rule, path + REQUIRED1, value, null);
+ }
+ required = (Boolean) value;
+ }
+
+
+ private void initPatternValue(Object value, Rule rule, String path) {
+ if (! (value instanceof String)) {
+ throw schemaError(PATTERN_NOTSTR, rule, path + PATTERN2, value, null);
+ }
+ pattern = (String)value;
+ Matcher m = Util.matcher(pattern, "\\A/(.*)/([mi]?[mi]?)\\z");
+ if (! m.find()) {
+ throw schemaError(PATTERN_NOTMATCH, rule, path + PATTERN2, 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 {
+ patternRegexp = Pattern.compile(pat, flag);
+ } catch (PatternSyntaxException ex) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), PATTERN_SYNTAX_EXCEPTION, ex);
+ throw schemaError(PATTERN_SYNTAXERR, rule, path + PATTERN2, value, null);
+ }
+ }
+
+
+ private void initEnumValue(Object value, Rule rule, String path) {
+ if (! (value instanceof List)) {
+ throw schemaError("enum.notseq", rule, path + ENUM1, value, null);
+ }
+ enumList = (List)value;
+ if (Types.isCollectionType(_type)) {
+ throw schemaError("enum.notscalar", rule, path, ENUM, null);
+ }
+ Map elemTable = new HashMap();
+ for (Iterator it = enumList.iterator(); it.hasNext(); ) {
+ Object elem = it.next();
+ if (! Util.isInstanceOf(elem, typeClass)) {
+ throw schemaError("enum.type.unmatch", rule, path + ENUM1, elem, new Object[] { Types.typeName(_type) });
+ }
+ if (elemTable.containsKey(elem)) {
+ throw schemaError("enum.duplicate", rule, path + ENUM1, elem, null);
+ }
+ elemTable.put(elem, Boolean.TRUE);
+ }
+ }
+
+
+ private void initAssertValue(Object value, Rule rule, String path) {
+ 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) {
+ if (! (value instanceof Map)) {
+ throw schemaError("range.notmap", rule, path + RANGE1, value, null);
+ }
+ if (Types.isCollectionType(_type) || "bool".equals(_type)) {
+ throw schemaError("range.notscalar", rule, path, RANGE2, null);
+ }
+ range = (Map)value;
+ for (Iterator it = range.keySet().iterator(); it.hasNext(); ) {
+ Object rkey = it.next();
+ Object rval = range.get(rkey);
+ if (MAX.equals(rkey) || MIN.equals(rkey) || rkey.equals(MAX_EX) || rkey.equals(MIN_EX)) {
+ if (! Util.isInstanceOf(rval, typeClass)) {
+ 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 + RANGE1, null, null);
+ }
+ if (range.containsKey(MIN) && range.containsKey(MIN_EX)) {
+ throw schemaError("range.twomin", rule, path + RANGE1, null, null);
+ }
+ //
+ Object max = range.get(MAX);
+ Object min = range.get(MIN);
+ Object maxEx = range.get(MAX_EX);
+ Object minEx = range.get(MIN_EX);
+ Object[] args;
+
+ if (max != null) {
+ if (min != null && Util.compareValues(max, min) < 0) {
+ args = new Object[] { max, min };
+ throw schemaError("range.maxltmin", rule, path + RANGE1, null, args);
+ } else if (minEx != null && Util.compareValues(max, minEx) <= 0) {
+ args = new Object[] { max, minEx };
+ throw schemaError("range.maxleminex", rule, path + RANGE1, null, args);
+ }
+ } else if (maxEx != null) {
+ if (min != null && Util.compareValues(maxEx, min) <= 0) {
+ args = new Object[] { maxEx, min };
+ throw schemaError("range.maxexlemin", rule, path + RANGE1, null, args);
+ } else if (minEx != null && Util.compareValues(maxEx, minEx) <= 0) {
+ args = new Object[] { maxEx, minEx };
+ throw schemaError("range.maxexleminex", rule, path + RANGE1, null, args);
+ }
+ }
+ }
+
+
+ private void initLengthValue(Object value, Rule rule, String path) {
+ if (! (value instanceof Map)) {
+ throw schemaError("length.notmap", rule, path + LENGTH1, value, null);
+ }
+ length = (Map)value;
+ if (! ("str".equals(_type) || "text".equals(_type))) {
+ throw schemaError("length.nottext", rule, path, LENGTH2, null);
+ }
+ for (String k : length.keySet()) {
+ Integer v = length.get(k);
+ if (MAX.equals(k) || MIN.equals(k) || k.equals(MAX_EX) || k.equals(MIN_EX)) {
+ if (v != null) {
+ throw schemaError("length.notint", rule, path + LENGTH3 + k, v, null);
+ }
+ } else {
+ throw schemaError("length.undefined", rule, path + LENGTH3 + k, k + ":", null);
+ }
+ }
+ if (length.containsKey(MAX) && length.containsKey(MAX_EX)) {
+ throw schemaError("length.twomax", rule, path + LENGTH1, null, null);
+ }
+ if (length.containsKey(MIN) && length.containsKey(MIN_EX)) {
+ throw schemaError("length.twomin", rule, path + LENGTH1, null, null);
+ }
+
+ Integer max = length.get(MAX);
+ Integer min = length.get(MIN);
+ Integer maxEx = length.get(MAX_EX);
+ Integer minEx = length.get(MIN_EX);
+ Object[] args;
+
+ if (max != null) {
+ if (min != null && max.compareTo(min) < 0) {
+ args = new Object[] { max, min };
+ throw schemaError("length.maxltmin", rule, path + LENGTH1, null, args);
+ } else if (minEx != null && max.compareTo(minEx) <= 0) {
+ args = new Object[] { max, minEx };
+ throw schemaError("length.maxleminex", rule, path + LENGTH1, null, args);
+ }
+ } else if (maxEx != null) {
+ if (min != null && maxEx.compareTo(min) <= 0) {
+ args = new Object[] { maxEx, min };
+ throw schemaError(LENGTH_MAXEXLEMIN, rule, path + LENGTH1, null, args);
+ } else if (minEx != null && maxEx.compareTo(minEx) <= 0) {
+ args = new Object[] { maxEx, minEx };
+ throw schemaError(LENGTH_MAXEXLEMINEX, rule, path + LENGTH1, null, args);
+ }
+ }
+ }
+
+ private void initIdentValue(Object value, Rule rule, String path) {
+ if (value == null || ! (value instanceof Boolean)) {
+ throw schemaError(IDENT_NOTBOOL, rule, path + IDENT2, value, null);
+ }
+ ident = (Boolean) value;
+ required = true;
+ if (Types.isCollectionType(_type)) {
+ throw schemaError(IDENT_NOTSCALAR, rule, path, IDENT1, null);
+ }
+ if (EMPTY_STRING.equals(path)) {
+ throw schemaError(IDENT_ONROOT, rule, SLASH, IDENT1, null);
+ }
+ if (parent == null || ! MAP.equals(parent.getType())) {
+ throw schemaError(IDENT_NOTMAP, rule, path, IDENT1, null);
+ }
+ }
+
+
+ private void initUniqueValue(Object value, Rule rule, String path) {
+ if (! (value instanceof Boolean)) {
+ throw schemaError(UNIQUE_NOTBOOL, rule, path + UNIQUE2, value, null);
+ }
+ unique = (Boolean) value;
+ if (Types.isCollectionType(_type)) {
+ throw schemaError(UNIQUE_NOTSCALAR, rule, path, UNIQUE1, null);
+ }
+ if (path.equals(EMPTY_STRING)) {
+ throw schemaError(UNIQUE_ONROOT, rule, SLASH, UNIQUE1, null);
+ }
+ }
+
+
+ private Rule initSequenceValue(Object value, Rule rule, String path, Map ruleTable) {
+ if (value != null && ! (value instanceof List)) {
+ throw schemaError(SEQUENCE_NOTSEQ, rule, path + SEQUENCE1, value.toString(), null);
+ }
+ sequence = (List)value;
+ if (sequence == null || sequence.isEmpty()) {
+ throw schemaError(SEQUENCE_NOELEM, rule, path + SEQUENCE1, value, null);
+ }
+ if (sequence.size() > 1) {
+ throw schemaError(SEQUENCE_TOOMANY, rule, path + SEQUENCE1, value, null);
+ }
+ Object elem = sequence.get(0);
+ if (elem == null) {
+ elem = new HashMap();
+ }
+ int i = 0;
+ rule = (Rule)ruleTable.get(elem);
+ if (rule == null) {
+ rule = new Rule(null, this);
+ rule.init(elem, path + SEQUENCE3 + i, ruleTable);
+ }
+ sequence = new ArrayList();
+ sequence.add(rule);
+ return rule;
+ }
+
+
+ private Rule initMappingValue(Object value, Rule rule, String path, Map ruleTable) {
+ // error check
+ if (value != null && !(value instanceof Map)) {
+ throw schemaError(MAPPING_NOTMAP, rule, path + MAPPING2, value.toString(), null);
+ }
+ Object defaultValue = null;
+ if (value instanceof Defaultable) {
+ defaultValue = ((Defaultable)value).getDefault();
+ }
+ if (value == null || ((Map)value).size() == 0 && defaultValue == null) {
+ throw schemaError(MAPPING_NOELEM, rule, path + MAPPING2, value, null);
+ }
+ // create hash of rule
+ _mapping = new DefaultableHashMap();
+ if (defaultValue != null) {
+ rule = (Rule)ruleTable.get(defaultValue);
+ if (rule == null) {
+ rule = new Rule(null, this);
+ rule.init(defaultValue, path + MAPPING3, ruleTable);
+ }
+ _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)ruleTable.get(v);
+ if (rule == null) {
+ rule = new Rule(null, this);
+ rule.init(v, path + MAPPING4 + k, ruleTable);
+ }
+ if ("=".equals(k)) {
+ _mapping.setDefault(rule);
+ } else {
+ _mapping.put(k, rule);
+ }
+ }
+ return rule;
+ }
+
+
+ private void checkConfliction(Map hash, Rule rule, String path) {
+ if ("seq".equals(_type)) {
+ if (! hash.containsKey(SEQUENCE)) {
+ throw schemaError("seq.nosequence", rule, path, null, null);
+ }
+ if (enumList != null) {
+ throw schemaError(SEQ_CONFLICT, rule, path, ENUM, null);
+ }
+ if (pattern != null) {
+ throw schemaError(SEQ_CONFLICT, rule, path, PATTERN1, null);
+ }
+ if (_mapping != null) {
+ throw schemaError(SEQ_CONFLICT, rule, path, MAPPING1, null);
+ }
+ if (range != null) {
+ throw schemaError(SEQ_CONFLICT, rule, path, RANGE2, null);
+ }
+ if (length != null) {
+ throw schemaError(SEQ_CONFLICT, rule, path, LENGTH2, null);
+ }
+ } else if (_type.equals(MAP)) {
+ if (! hash.containsKey(MAPPING)) {
+ throw schemaError("map.nomapping", rule, path, null, null);
+ }
+ if (enumList != null) {
+ throw schemaError(MAP_CONFLICT, rule, path, ENUM, null);
+ }
+ if (pattern != null) {
+ throw schemaError(MAP_CONFLICT, rule, path, PATTERN1, null);
+ }
+ if (sequence != null) {
+ throw schemaError(MAP_CONFLICT, rule, path, SEQUENCE2, null);
+ }
+ if (range != null) {
+ throw schemaError(MAP_CONFLICT, rule, path, RANGE2, null);
+ }
+ if (length != null) {
+ throw schemaError(MAP_CONFLICT, rule, path, LENGTH2, null);
+ }
+ } else {
+ if (sequence != null) {
+ throw schemaError(SCALAR_CONFLICT, rule, path, SEQUENCE2, null);
+ }
+ if (_mapping != null) {
+ throw schemaError(SCALAR_CONFLICT, rule, path, MAPPING1, null);
+ }
+ if (enumList != null) {
+ if (range != null) {
+ throw schemaError(ENUM_CONFLICT, rule, path, RANGE2, null);
+ }
+ if (length != null) {
+ throw schemaError(ENUM_CONFLICT, rule, path, LENGTH2, null);
+ }
+ if (pattern != null) {
+ throw schemaError(ENUM_CONFLICT, rule, path, PATTERN1, null);
+ }
+ }
+ }
+ }
+
+ public String inspect() {
+ StringBuilder sb = new StringBuilder();
+ int level = 0;
+ Map done = new IdentityHashMap();
+ inspect(sb, level, done);
+ return sb.toString();
+ }
+
+ private void inspect(StringBuilder sb, int level, Map done) {
+ done.put(this, Boolean.TRUE);
+ String indent = Util.repeatString(TWO_SPACES, level);
+ if (name != null) {
+ sb.append(indent).append(NAME1).append(name).append("\n");
+ }
+ if (desc != null) {
+ sb.append(indent).append(DESC1).append(desc).append("\n");
+ }
+ if (_type != null) {
+ sb.append(indent).append(TYPE2).append(_type).append("\n");
+ }
+ if (required) {
+ sb.append(indent).append(REQUIRED2).append(required).append("\n");
+ }
+ if (pattern != null) {
+ sb.append(indent).append(PATTERN3).append(pattern).append("\n");
+ }
+ if (patternRegexp != null) {
+ sb.append(indent).append(REGEXP).append(patternRegexp).append("\n");
+ }
+ if (_assert != null) {
+ sb.append(indent).append(ASSERT1).append(_assert).append("\n");
+ }
+ if (ident) {
+ sb.append(indent).append(IDENT3).append(ident).append("\n");
+ }
+ if (unique) {
+ sb.append(indent).append(UNIQUE3).append(unique).append("\n");
+ }
+ if (enumList != null) {
+ appendEnums(sb, indent);
+ }
+ if (range != null) {
+ appendRange(sb, indent);
+ }
+ if (sequence != null) {
+ appendSequence(sb, level, done, indent);
+ }
+ if (_mapping != null) {
+ appendMapping(sb, level, done, indent);
+ }
+ }
+
+ private void appendEnums(StringBuilder sb, String indent) {
+ sb.append(indent).append(ENUM2);
+ for (Object anEnumList : enumList) {
+ sb.append(indent).append(" - ").append(anEnumList.toString()).append("\n");
+ }
+ }
+
+ private void appendMapping(StringBuilder sb, int level, Map done, String indent) {
+ for (Object o : _mapping.entrySet()) {
+ Map.Entry entry = (Map.Entry) o;
+ 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);
+ }
+ }
+ }
+
+ private void appendSequence(StringBuilder sb, int level, Map done, String indent) {
+ for (Object aSequence : sequence) {
+ Rule rule = (Rule) aSequence;
+ if (done.containsKey(rule)) {
+ sb.append(indent).append(" ").append("- ...\n");
+ } else {
+ sb.append(indent).append(" ").append("- \n");
+ rule.inspect(sb, level + 2, done);
+ }
+ }
+ }
+
+ private void appendRange(StringBuilder sb, String indent) {
+ sb.append(indent).append(RANGE3);
+ String[] keys = new String[] {MAX, MAX_EX, MIN, MIN_EX, };
+ String colon = EMPTY_STRING;
+ for (String key : keys) {
+ Object val = range.get(key);
+ if (val != null) {
+ sb.append(colon).append(key).append(": ").append(val);
+ colon = ", ";
+ }
+ }
+ sb.append(" }\n");
+ }
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/SchemaException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/SchemaException.java
new file mode 100644
index 0000000..70dafe9
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/SchemaException.java
@@ -0,0 +1,17 @@
+/*
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * exception class thrown by Rule constructor
+ */
+public class SchemaException extends BaseException {
+ private static final long serialVersionUID = 4750598728284538818L;
+
+ public SchemaException(String message, String ypath, Object value, Rule rule) {
+ super(message, ypath, value, rule);
+ }
+
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/SyntaxException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/SyntaxException.java
new file mode 100644
index 0000000..8c36b66
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/Types.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Types.java
new file mode 100644
index 0000000..cce8e1e
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/Types.java
@@ -0,0 +1,105 @@
+/*
+ * @(#)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("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");
+ }
+
+
+ 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/dcaedt_validator/kwalify/src/main/java/kwalify/Util.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Util.java
new file mode 100644
index 0000000..da34087
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/Util.java
@@ -0,0 +1,456 @@
+/*
+ * 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;
+
+public class Util {
+ 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;
+ private static HashMap<String,Pattern> __patterns = new HashMap<>();
+
+ private Util(){
+ // You shouldn't instantiate this class
+ }
+
+ /**
+ * inspect List or Map
+ */
+ public static String inspect(Object obj) {
+ StringBuilder sb = new StringBuilder();
+ inspect(obj, sb, null);
+ return sb.toString();
+ }
+
+ private static void inspect(Object obj, StringBuilder sb, IdentityHashMap done) {
+ if (obj == null) {
+ sb.append("nil"); // null?
+ } else if (obj instanceof String) {
+ inspect((String)obj, sb);
+ } else if (obj instanceof IdentityHashMap) {
+ 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);
+ }
+ } else {
+ sb.append(obj.toString());
+ }
+ }
+
+ private static void inspect(Map map, StringBuilder sb, IdentityHashMap 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, StringBuilder sb) {
+ 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, StringBuilder sb) {
+ 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('"');
+ }
+
+ /**
+ * 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 = __patterns.get(regexp);
+ if (pat == null) {
+ pat = Pattern.compile(regexp);
+ __patterns.put(regexp, pat);
+ }
+ return pat.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();
+ }
+
+ /**
+ * split string into list of line
+ */
+ public static List toListOfLines(String str) {
+ List<String> 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;
+ }
+
+ /**
+ * 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 (Class anInterface : interfaces) {
+ if (anInterface == 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
+ */
+ private static String readFile(String filename, String encoding) throws IOException {
+ String content;
+ try (InputStream stream = new FileInputStream(filename)){
+ content = readInputStream(stream, encoding);
+ }
+ return content;
+ }
+
+ public static String readInputStream(InputStream stream) throws IOException {
+ String encoding = System.getProperty("file.encoding");
+ return readInputStream(stream, encoding);
+ }
+
+ private static String readInputStream(InputStream stream, String encoding) throws IOException {
+ String content;
+ try (Reader reader = new InputStreamReader(stream, encoding)){
+ StringBuilder sb = new StringBuilder();
+ int ch;
+ while ((ch = reader.read()) >= 0) {
+ sb.append((char)ch);
+ }
+ content = sb.toString();
+ }
+ return content;
+ }
+
+ public static String untabify(CharSequence str) {
+ int tabWidth = 8;
+ StringBuilder sb = new StringBuilder();
+ int len = str.length();
+ int col = -1;
+ for (int i = 0; i < len; i++) {
+ col = ++col % tabWidth;
+ char ch = str.charAt(i);
+
+ switch (ch) {
+ case '\t':
+ appendTabAsSpaces(tabWidth, sb, col);
+ col = -1;
+ break;
+ case '\n':
+ sb.append(ch);
+ col = -1;
+ break;
+ default:
+ sb.append(ch);
+ }
+ }
+ return sb.toString();
+ }
+
+ private static void appendTabAsSpaces(int tabWidth, StringBuilder sb, int col) {
+ int n = tabWidth - col;
+ while (--n >= 0) {
+ sb.append(' ');
+ }
+ }
+
+ public static int compareValues(Object value1, Object value2) {
+ 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 :
+ boolean b1 = (Boolean) value1;
+ boolean b2 = (Boolean) value2;
+ int ret = b1 ? 1 : -1;
+ return (b1 == b2) ? 0 : ret;
+ 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 Double.compare(d1, d2);
+ default:
+ 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) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < times; i++) {
+ sb.append(str);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 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<String, Object> options = new HashMap<>();
+ Map<String, Object> properties = new HashMap<>();
+ String[] filenames;
+
+ 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;
+ 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");
+ }
+ }
+ }
+ }
+
+ 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/dcaedt_validator/kwalify/src/main/java/kwalify/ValidationException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/ValidationException.java
new file mode 100644
index 0000000..911f9e1
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/ValidationException.java
@@ -0,0 +1,15 @@
+/*
+ * @(#)ValidationException.java $Rev: 4 $ $Release: 0.5.1 $
+ *
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+public class ValidationException extends BaseException {
+ private static final long serialVersionUID = -2991121377463453973L;
+
+ public ValidationException(String message, String path, Object value, Rule rule) {
+ super(message, path, value, rule);
+ }
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/Validator.java b/dcaedt_validator/kwalify/src/main/java/kwalify/Validator.java
new file mode 100644
index 0000000..e0f5af0
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/Validator.java
@@ -0,0 +1,382 @@
+/*
+ * @(#)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 {
+ 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();
+ }
+ }
+
+
+ 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));
+ 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));
+ 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;
+ }
+ }
+
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/YamlParser.java b/dcaedt_validator/kwalify/src/main/java/kwalify/YamlParser.java
new file mode 100644
index 0000000..b5789d3
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/YamlParser.java
@@ -0,0 +1,101 @@
+/*
+ * 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.Iterator;
+
+/**
+ * yaml parser which can keep line number of path.
+ */
+public class YamlParser extends PlainYamlParser {
+ private Map linenumsTable = new IdentityHashMap(); // object => sequence or mapping
+ private int firstLinenum = -1;
+ private Object document = null;
+
+ YamlParser(String yamlStr) {
+ super(yamlStr);
+ }
+
+ public Object parse() throws SyntaxException {
+ document = super.parse();
+ return document;
+ }
+
+ protected String getLine() {
+ String line = super.getLine();
+ if (firstLinenum < 0) {
+ firstLinenum = currentLineNumber();
+ }
+ return line;
+ }
+
+
+ private int getPathLineNumber(String ypath) throws InvalidPathException {
+ if (document == null) {
+ return -1;
+ }
+ if (ypath.length() == 0 || "/".equals(ypath)) {
+ return 1;
+ }
+ String[] elems = ypath.split("/");
+ String lastElem = elems.length > 0 ? elems[elems.length - 1] : null;
+ int i = ypath.charAt(0) == '/' ? 1 : 0;
+ int len = elems.length - 1;
+ Object documentCollection = this.document; // collection
+ for ( ; i < len ; i++) {
+ if (documentCollection == null) {
+ throw new InvalidPathException(ypath);
+ } else if (documentCollection instanceof Map) {
+ documentCollection = ((Map)documentCollection).get(elems[i]);
+ } else if (documentCollection instanceof List) {
+ int index = Integer.parseInt(elems[i]);
+ if (index < 0 || ((List)documentCollection).size() < index) {
+ throw new InvalidPathException(ypath);
+ }
+ documentCollection = ((List)documentCollection).get(index);
+ } else {
+ throw new InvalidPathException(ypath);
+ }
+ }
+
+ if (documentCollection == null) {
+ throw new InvalidPathException(ypath);
+ }
+ Object linenums = linenumsTable.get(documentCollection); // Map or List
+ int linenum;
+ if (documentCollection instanceof Map) {
+ assert linenums instanceof Map;
+ Object d = ((Map)linenums).get(lastElem);
+ linenum = (Integer) d;
+ } else if (documentCollection instanceof List) {
+ assert linenums instanceof List;
+ int index = Integer.parseInt(lastElem);
+ if (index < 0 || ((List)linenums).size() <= index) {
+ throw new InvalidPathException(ypath);
+ }
+ Object d = ((List)linenums).get(index);
+ linenum = (Integer) d;
+ } 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 Map createMapping() {
+ Map map = super.createMapping();
+ linenumsTable.put(map, new HashMap());
+ return map;
+ }
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/YamlSyntaxException.java b/dcaedt_validator/kwalify/src/main/java/kwalify/YamlSyntaxException.java
new file mode 100644
index 0000000..a8b1011
--- /dev/null
+++ b/dcaedt_validator/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/dcaedt_validator/kwalify/src/main/java/kwalify/YamlUtil.java b/dcaedt_validator/kwalify/src/main/java/kwalify/YamlUtil.java
new file mode 100644
index 0000000..4b15213
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/YamlUtil.java
@@ -0,0 +1,20 @@
+/*
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+/**
+ * utilify class for yaml.
+ */
+public class YamlUtil {
+
+ private YamlUtil() {
+ //hides implicit public
+ }
+
+ public static Object load(String yamlStr) throws SyntaxException {
+ PlainYamlParser parser = new PlainYamlParser(yamlStr);
+ return parser.parse();
+ }
+}
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/messages.properties b/dcaedt_validator/kwalify/src/main/java/kwalify/messages.properties
new file mode 100644
index 0000000..5734461
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/messages.properties
@@ -0,0 +1,108 @@
+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 \ No newline at end of file
diff --git a/dcaedt_validator/kwalify/src/main/resources/kwalify/messages.properties b/dcaedt_validator/kwalify/src/main/resources/kwalify/messages.properties
new file mode 100644
index 0000000..edb3fd7
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/resources/kwalify/messages.properties
@@ -0,0 +1,107 @@
+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.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 \ No newline at end of file