diff options
author | Stone, Avi (as206k) <as206k@att.com> | 2018-04-12 15:46:31 +0300 |
---|---|---|
committer | Stone, Avi (as206k) <as206k@att.com> | 2018-04-12 15:49:38 +0300 |
commit | 5032434b101f25fa44d2e1f8dc8393e30af1ed4f (patch) | |
tree | 2dc7d37a8048e025c7412af080640da4c9a22b65 /dcaedt_validator/kwalify/src | |
parent | 2205633792f95f46a02bbf8f87f0c2637265d924 (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')
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 |