diff options
author | Rafael H. Schloming <rhs@apache.org> | 2010-01-22 14:26:11 +0000 |
---|---|---|
committer | Rafael H. Schloming <rhs@apache.org> | 2010-01-22 14:26:11 +0000 |
commit | 631dfd9bd1b96540ccdc5d2419f2c47a9e15253e (patch) | |
tree | de56c5158b51649270fbcc194d33cd3bbd5c606f | |
parent | 578ab4e8631e778bfdbb4f88b030314471394d53 (diff) | |
download | qpid-python-631dfd9bd1b96540ccdc5d2419f2c47a9e15253e.tar.gz |
added boolean literals to java & python address parser; added validation to python address usage
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@902095 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java | 12 | ||||
-rw-r--r-- | java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java | 4 | ||||
-rw-r--r-- | python/qpid/address.py | 8 | ||||
-rw-r--r-- | python/qpid/driver.py | 48 | ||||
-rw-r--r-- | python/qpid/tests/address.py | 4 | ||||
-rw-r--r-- | python/qpid/tests/messaging.py | 32 | ||||
-rw-r--r-- | python/qpid/validator.py | 68 |
7 files changed, 162 insertions, 14 deletions
diff --git a/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java b/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java index 609387deb6..7b31436ba0 100644 --- a/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java +++ b/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java @@ -47,6 +47,8 @@ public class AddressParser extends Parser private static Token.Type SLASH = lxi.define("SLASH", "/"); private static Token.Type COMMA = lxi.define("COMMA", ","); private static Token.Type NUMBER = lxi.define("NUMBER", "[+-]?[0-9]*\\.?[0-9]+"); + private static Token.Type TRUE = lxi.define("TRUE", "True"); + private static Token.Type FALSE = lxi.define("FALSE", "False"); private static Token.Type ID = lxi.define("ID", "[a-zA-Z_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?"); private static Token.Type STRING = lxi.define("STRING", "\"(?:[^\\\"]|\\.)*\"|'(?:[^\\']|\\.)*'"); private static Token.Type ESC = lxi.define("ESC", "\\\\[^ux]|\\\\x[0-9a-fA-F][0-9a-fA-F]|\\\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]"); @@ -198,6 +200,14 @@ public class AddressParser extends Parser return Integer.decode(value); } } + else if (type == TRUE) + { + return true; + } + else if (type == FALSE) + { + return false; + } else { return value; @@ -315,7 +325,7 @@ public class AddressParser extends Parser Object value() { - if (matches(NUMBER, STRING, ID)) + if (matches(NUMBER, STRING, ID, TRUE, FALSE)) { return tok2obj(eat()); } diff --git a/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java b/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java index 6fc41dc0f9..63d2de21b2 100644 --- a/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java +++ b/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java @@ -109,6 +109,10 @@ public class JAddr { return pprint_string((String) obj); } + else if (obj instanceof Boolean) + { + return ((Boolean) obj).booleanValue() ? "True" : "False"; + } else if (obj == null) { return "None"; diff --git a/python/qpid/address.py b/python/qpid/address.py index bda7157a5f..ab0fe8221a 100644 --- a/python/qpid/address.py +++ b/python/qpid/address.py @@ -31,6 +31,8 @@ SEMI = l.define("SEMI", r";") SLASH = l.define("SLASH", r"/") COMMA = l.define("COMMA", r",") NUMBER = l.define("NUMBER", r'[+-]?[0-9]*\.?[0-9]+') +TRUE = l.define("TRUE", r'True') +FALSE = l.define("FALSE", r'False') ID = l.define("ID", r'[a-zA-Z_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?') STRING = l.define("STRING", r""""(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*'""") ESC = l.define("ESC", r"\\[^ux]|\\x[0-9a-fA-F][0-9a-fA-F]|\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]") @@ -59,6 +61,10 @@ def tok2str(tok): def tok2obj(tok): if tok.type in (STRING, NUMBER): return eval(tok.value) + elif tok.type == TRUE: + return True + elif tok.type == FALSE: + return False else: return tok.value @@ -127,7 +133,7 @@ class AddressParser(Parser): return (key, val) def value(self): - if self.matches(NUMBER, STRING, ID): + if self.matches(NUMBER, STRING, ID, TRUE, FALSE): return tok2obj(self.eat()) elif self.matches(LBRACE): return self.map() diff --git a/python/qpid/driver.py b/python/qpid/driver.py index 858e2922ea..2feba15918 100644 --- a/python/qpid/driver.py +++ b/python/qpid/driver.py @@ -28,6 +28,7 @@ from ops import * from selector import Selector from threading import Condition, Thread from util import connect +from validator import Map, Types, Values log = getLogger("qpid.messaging") rawlog = getLogger("qpid.messaging.io.raw") @@ -474,6 +475,9 @@ class Driver: if _snd.options is None: _snd.options = {} + if not self.validate_options(_snd): + return + def do_link(type, subtype): if type == "topic": _snd._exchange = _snd.name @@ -527,6 +531,9 @@ class Driver: if _rcv.options is None: _rcv.options = {} + if not self.validate_options(_rcv): + return + def do_link(type, subtype): if type == "topic": _rcv._queue = "%s.%s" % (rcv.session.name, _rcv.destination) @@ -567,6 +574,33 @@ class Driver: sst.write_cmd(MessageCancel(_rcv.destination), do_unlink) _rcv.canceled = True + POLICIES = Values("always", "sender", "receiver", "never") + + OPTS = Map({ + "create": POLICIES, + "delete": POLICIES, + "assert": POLICIES, + "type": Types(basestring), + "node-properties": Map({ + "type": Values("queue", "topic"), + "durable": Types(bool), + "x-properties": Map({ + "type": Types(basestring), + "bindings": Types(list) + }, + restricted=False) + }) + }) + + def validate_options(self, lnk): + err = Driver.OPTS.validate(lnk.options) + if err: + lnk.target.error = ("error in options: %s" % err,) + lnk.target.closed = True + return False + else: + return True + def resolve_declare(self, sst, lnk, dir, action): def do_resolved(er, qr): if er.not_found and not qr.queue: @@ -598,14 +632,10 @@ class Driver: sst.write_query(QueueQuery(name), do_action) def declare(self, sst, name, options, action): - opts = dict(options) - props = dict(opts.pop("node-properties", {})) - durable = props.pop("durable", DURABLE_DEFAULT) - type = props.pop("type", "queue") - xprops = dict(props.pop("x-properties", {})) - - if props: - return ("unrecognized option(s): %s" % "".join(props.keys()),) + props = options.get("node-properties", {}) + durable = props.get("durable", DURABLE_DEFAULT) + type = props.get("type", "queue") + xprops = props.get("x-properties", {}) if type == "topic": cmd = ExchangeDeclare(exchange=name, durable=durable) @@ -613,7 +643,7 @@ class Driver: cmd = QueueDeclare(queue=name, durable=durable) bindings = xprops.pop("bindings", []) else: - return ("unrecognized type, must be topic or queue: %s" % type,) + raise ValueError(type) for f in cmd.FIELDS: if f.name != "arguments" and xprops.has_key(f.name): diff --git a/python/qpid/tests/address.py b/python/qpid/tests/address.py index 07349d8c6c..7e6c6a5ee5 100644 --- a/python/qpid/tests/address.py +++ b/python/qpid/tests/address.py @@ -303,3 +303,7 @@ class AddressTests(ParserBase, Test): def testMap3(self): self.valid('name/subject; { "foo.bar": value }', "name", "subject", {"foo.bar": "value"}) + + def testBoolean(self): + self.valid("name/subject; { true: True, false: False }", + "name", "subject", {"true": True, "false": False}) diff --git a/python/qpid/tests/messaging.py b/python/qpid/tests/messaging.py index 683bb574ee..ba33ab9e80 100644 --- a/python/qpid/tests/messaging.py +++ b/python/qpid/tests/messaging.py @@ -580,12 +580,38 @@ class AddressTests(Base): def setup_session(self): return self.conn.session() - def testBadOption(self): - snd = self.ssn.sender("test-bad-option; {create: always, node-properties: {this-property-does-not-exist: 3}}") + def badOption(self, options, error): + snd = self.ssn.sender("test-bad-options-snd; %s" % options) try: snd.send("ping") + assert False except SendError, e: - assert "unrecognized option" in str(e) + assert "error in options: %s" % error == str(e), e + + rcv = self.ssn.receiver("test-bad-options-rcv; %s" % options) + try: + rcv.fetch(timeout=0) + assert False + except ReceiveError, e: + assert "error in options: %s" % error == str(e), e + + def testIllegalKey(self): + self.badOption("{create: always, node-properties: " + "{this-property-does-not-exist: 3}}", + "node-properties: this-property-does-not-exist: " + "illegal key") + + def testWrongValue(self): + self.badOption("{create: asdf}", "create: asdf not in " + "('always', 'sender', 'receiver', 'never')") + + def testWrongType1(self): + self.badOption("{node-properties: asdf}", + "node-properties: asdf is not a map") + + def testWrongType2(self): + self.badOption("{node-properties: {durable: []}}", + "node-properties: durable: [] is not a bool") def testCreateQueue(self): snd = self.ssn.sender("test-create-queue; {create: always, delete: always, " diff --git a/python/qpid/validator.py b/python/qpid/validator.py new file mode 100644 index 0000000000..8bd1c98736 --- /dev/null +++ b/python/qpid/validator.py @@ -0,0 +1,68 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +class Values: + + def __init__(self, *values): + self.values = values + + def validate(self, o): + if not o in self.values: + return "%s not in %s" % (o, self.values) + + def __str__(self): + return self.value + +class Types: + + def __init__(self, *types): + self.types = types + + def validate(self, o): + for t in self.types: + if isinstance(o, t): + return + if len(self.types) == 1: + return "%s is not a %s" % (o, self.types[0].__name__) + else: + return "%s is not one of: %s" % (o, ", ".join([t.__name__ for t in self.types])) + +class Map: + + def __init__(self, map, restricted=True): + self.map = map + self.restricted = restricted + + def validate(self, o): + errors = [] + + if not hasattr(o, "get"): + return "%s is not a map" % o + + for k, t in self.map.items(): + v = o.get(k) + if v is not None: + err = t.validate(v) + if err: errors.append("%s: %s" % (k, err)) + if self.restricted: + for k in o: + if not k in self.map: + errors.append("%s: illegal key" % k) + if errors: + return ", ".join(errors) |