summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael H. Schloming <rhs@apache.org>2010-01-22 14:26:11 +0000
committerRafael H. Schloming <rhs@apache.org>2010-01-22 14:26:11 +0000
commit631dfd9bd1b96540ccdc5d2419f2c47a9e15253e (patch)
treede56c5158b51649270fbcc194d33cd3bbd5c606f
parent578ab4e8631e778bfdbb4f88b030314471394d53 (diff)
downloadqpid-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.java12
-rw-r--r--java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java4
-rw-r--r--python/qpid/address.py8
-rw-r--r--python/qpid/driver.py48
-rw-r--r--python/qpid/tests/address.py4
-rw-r--r--python/qpid/tests/messaging.py32
-rw-r--r--python/qpid/validator.py68
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)