summaryrefslogtreecommitdiff
path: root/qpid/java/common/src/main/java/org/apache/qpid/messaging
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/common/src/main/java/org/apache/qpid/messaging')
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/Address.java75
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java380
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java97
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LexError.java37
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexer.java84
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexicon.java103
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LineInfo.java93
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/ParseError.java58
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java85
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/PyPrint.java146
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Token.java106
11 files changed, 1264 insertions, 0 deletions
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/Address.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/Address.java
new file mode 100644
index 0000000000..2c7fe7b8ed
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/Address.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging;
+
+import java.util.Map;
+
+import org.apache.qpid.messaging.util.AddressParser;
+
+import static org.apache.qpid.messaging.util.PyPrint.pprint;
+
+
+/**
+ * Address
+ *
+ */
+
+public class Address
+{
+
+ public static Address parse(String address)
+ {
+ return new AddressParser(address).parse();
+ }
+
+ private String name;
+ private String subject;
+ private Map options;
+
+ public Address(String name, String subject, Map options)
+ {
+ this.name = name;
+ this.subject = subject;
+ this.options = options;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getSubject()
+ {
+ return subject;
+ }
+
+ public Map getOptions()
+ {
+ return options;
+ }
+
+ public String toString()
+ {
+ return String.format("%s/%s; %s", pprint(name), pprint(subject),
+ pprint(options));
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java
new file mode 100644
index 0000000000..7b31436ba0
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/AddressParser.java
@@ -0,0 +1,380 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.messaging.Address;
+
+
+/**
+ * AddressParser
+ *
+ */
+
+public class AddressParser extends Parser
+{
+
+ private static Lexicon lxi = new Lexicon();
+
+ private static Token.Type LBRACE = lxi.define("LBRACE", "\\{");
+ private static Token.Type RBRACE = lxi.define("RBRACE", "\\}");
+ private static Token.Type LBRACK = lxi.define("LBRACK", "\\[");
+ private static Token.Type RBRACK = lxi.define("RBRACK", "\\]");
+ private static Token.Type COLON = lxi.define("COLON", ":");
+ private static Token.Type SEMI = lxi.define("SEMI", ";");
+ 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]");
+ private static Token.Type SYM = lxi.define("SYM", "[.#*%@$^!+-]");
+ private static Token.Type WSPACE = lxi.define("WSPACE", "[\\s]+");
+ private static Token.Type EOF = lxi.eof("EOF");
+
+ private static Lexer LEXER = lxi.compile();
+
+ public static List<Token> lex(String input)
+ {
+ return LEXER.lex(input);
+ }
+
+ static List<Token> wlex(String input)
+ {
+ List<Token> tokens = new ArrayList<Token>();
+ for (Token t : lex(input))
+ {
+ if (t.getType() != WSPACE)
+ {
+ tokens.add(t);
+ }
+ }
+ return tokens;
+ }
+
+ static String unquote(String st, Token tok)
+ {
+ StringBuilder result = new StringBuilder();
+ for (int i = 1; i < st.length() - 1; i++)
+ {
+ char ch = st.charAt(i);
+ if (ch == '\\')
+ {
+ char code = st.charAt(i+1);
+ switch (code)
+ {
+ case '\n':
+ break;
+ case '\\':
+ result.append('\\');
+ break;
+ case '\'':
+ result.append('\'');
+ break;
+ case '"':
+ result.append('"');
+ break;
+ case 'a':
+ result.append((char) 0x07);
+ break;
+ case 'b':
+ result.append((char) 0x08);
+ break;
+ case 'f':
+ result.append('\f');
+ break;
+ case 'n':
+ result.append('\n');
+ break;
+ case 'r':
+ result.append('\r');
+ break;
+ case 't':
+ result.append('\t');
+ break;
+ case 'u':
+ result.append(decode(st.substring(i+2, i+6)));
+ i += 4;
+ break;
+ case 'v':
+ result.append((char) 0x0b);
+ break;
+ case 'o':
+ result.append(decode(st.substring(i+2, i+4), 8));
+ i += 2;
+ break;
+ case 'x':
+ result.append(decode(st.substring(i+2, i+4)));
+ i += 2;
+ break;
+ default:
+ throw new ParseError(tok);
+ }
+ i += 1;
+ }
+ else
+ {
+ result.append(ch);
+ }
+ }
+
+ return result.toString();
+ }
+
+ static char[] decode(String hex)
+ {
+ return decode(hex, 16);
+ }
+
+ static char[] decode(String code, int radix)
+ {
+ return Character.toChars(Integer.parseInt(code, radix));
+ }
+
+ static String tok2str(Token tok)
+ {
+ Token.Type type = tok.getType();
+ String value = tok.getValue();
+
+ if (type == STRING)
+ {
+ return unquote(value, tok);
+ }
+ else if (type == ESC)
+ {
+ if (value.charAt(1) == 'x' || value.charAt(1) == 'u')
+ {
+ return new String(decode(value.substring(2)));
+ }
+ else
+ {
+ return value.substring(1);
+ }
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ static Object tok2obj(Token tok)
+ {
+ Token.Type type = tok.getType();
+ String value = tok.getValue();
+ if (type == STRING)
+ {
+ return unquote(value, tok);
+ }
+ else if (type == NUMBER)
+ {
+ if (value.indexOf('.') >= 0)
+ {
+ return Double.valueOf(value);
+ }
+ else
+ {
+ return Integer.decode(value);
+ }
+ }
+ else if (type == TRUE)
+ {
+ return true;
+ }
+ else if (type == FALSE)
+ {
+ return false;
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ static String toks2str(List<Token> toks)
+ {
+ if (toks.size() > 0)
+ {
+ StringBuilder result = new StringBuilder();
+ for (Token t : toks)
+ {
+ result.append(tok2str(t));
+ }
+ return result.toString();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public AddressParser(String input)
+ {
+ super(wlex(input));
+ }
+
+ public Address parse()
+ {
+ Address result = address();
+ eat(EOF);
+ return result;
+ }
+
+ public Address address()
+ {
+ String name = toks2str(eat_until(SLASH, SEMI, EOF));
+
+ if (name == null)
+ {
+ throw new ParseError(next());
+ }
+
+ String subject;
+ if (matches(SLASH))
+ {
+ eat(SLASH);
+ subject = toks2str(eat_until(SEMI, EOF));
+ }
+ else
+ {
+ subject = null;
+ }
+
+ Map options;
+ if (matches(SEMI))
+ {
+ eat(SEMI);
+ options = map();
+ }
+ else
+ {
+ options = null;
+ }
+
+ return new Address(name, subject, options);
+ }
+
+ public Map<Object,Object> map()
+ {
+ eat(LBRACE);
+
+ Map<Object,Object> result = new HashMap<Object,Object>();
+ while (true)
+ {
+ if (matches(NUMBER, STRING, ID, LBRACE, LBRACK))
+ {
+ keyval(result);
+ if (matches(COMMA))
+ {
+ eat(COMMA);
+ }
+ else if (matches(RBRACE))
+ {
+ break;
+ }
+ else
+ {
+ throw new ParseError(next(), COMMA, RBRACE);
+ }
+ }
+ else if (matches(RBRACE))
+ {
+ break;
+ }
+ else
+ {
+ throw new ParseError(next(), NUMBER, STRING, ID, LBRACE, LBRACK,
+ RBRACE);
+ }
+ }
+
+ eat(RBRACE);
+ return result;
+ }
+
+ void keyval(Map<Object,Object> map)
+ {
+ Object key = value();
+ eat(COLON);
+ Object val = value();
+ map.put(key, val);
+ }
+
+ Object value()
+ {
+ if (matches(NUMBER, STRING, ID, TRUE, FALSE))
+ {
+ return tok2obj(eat());
+ }
+ else if (matches(LBRACE))
+ {
+ return map();
+ }
+ else if (matches(LBRACK))
+ {
+ return list();
+ }
+ else
+ {
+ throw new ParseError(next(), NUMBER, STRING, ID, LBRACE, LBRACK);
+ }
+ }
+
+ List<Object> list()
+ {
+ eat(LBRACK);
+
+ List<Object> result = new ArrayList<Object>();
+
+ while (true)
+ {
+ if (matches(RBRACK))
+ {
+ break;
+ }
+ else
+ {
+ result.add(value());
+ if (matches(COMMA))
+ {
+ eat(COMMA);
+ }
+ else if (matches(RBRACK))
+ {
+ break;
+ }
+ else
+ {
+ throw new ParseError(next(), COMMA, RBRACK);
+ }
+ }
+ }
+
+ eat(RBRACK);
+ return result;
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java
new file mode 100644
index 0000000000..93df052af1
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/JAddr.java
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import java.io.InputStreamReader;
+
+import java.util.List;
+
+import org.apache.qpid.messaging.Address;
+import org.apache.qpid.messaging.util.ParseError;
+import org.apache.qpid.messaging.util.Token;
+
+import static org.apache.qpid.messaging.util.PyPrint.pprint;
+
+
+/**
+ * JAddr
+ *
+ */
+
+public class JAddr
+{
+
+ public static final void main(String[] args) throws Exception
+ {
+ StringBuilder addr = new StringBuilder();
+ InputStreamReader reader = new InputStreamReader(System.in);
+
+ char[] buf = new char[1024];
+ while (true)
+ {
+ int n = reader.read(buf, 0, buf.length);
+ if (n < 0)
+ {
+ break;
+ }
+ addr.append(buf, 0, n);
+ }
+
+ if ("parse".equals(args[0]))
+ {
+ try
+ {
+ Address address = Address.parse(addr.toString());
+ System.out.println(pprint_address(address));
+ }
+ catch (ParseError e)
+ {
+ System.out.println(String.format("ERROR: %s", e.getMessage()));
+ }
+ }
+ else
+ {
+ List<Token> tokens = AddressParser.lex(addr.toString());
+ for (Token t : tokens)
+ {
+ String value = t.getValue();
+ if (value != null)
+ {
+ value = value.replace("\\", "\\\\").replace("\n", "\\n");
+ System.out.println(String.format("%s:%s:%s", t.getType(), t.getPosition(), value));
+ }
+ else
+ {
+ System.out.println(String.format("%s:%s", t.getType(), t.getPosition()));
+ }
+ }
+ }
+ }
+
+ private static String pprint_address(Address addr)
+ {
+ return String.format("NAME: %s\nSUBJECT: %s\nOPTIONS: %s",
+ pprint(addr.getName()),
+ pprint(addr.getSubject()),
+ pprint(addr.getOptions()));
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LexError.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LexError.java
new file mode 100644
index 0000000000..b8d346dca4
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LexError.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+
+/**
+ * LexError
+ *
+ */
+
+public class LexError extends RuntimeException
+{
+
+ public LexError(String msg)
+ {
+ super(msg);
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexer.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexer.java
new file mode 100644
index 0000000000..8226cc77cb
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexer.java
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Lexer
+ *
+ */
+
+public class Lexer
+{
+
+ private List<Token.Type> types;
+ private Token.Type eof;
+ private Pattern rexp;
+
+ public Lexer(List<Token.Type> types, Token.Type eof, Pattern rexp)
+ {
+ this.types = types;
+ this.eof = eof;
+ this.rexp = rexp;
+ }
+
+ public List<Token> lex(final String st)
+ {
+ List<Token> tokens = new ArrayList<Token>();
+
+ int position = 0;
+ Matcher m = rexp.matcher(st);
+ OUTER: while (position < st.length())
+ {
+ m.region(position, st.length());
+ if (m.lookingAt())
+ {
+ for (int i = 1; i <= m.groupCount(); i++)
+ {
+ String value = m.group(i);
+ if (value != null)
+ {
+ tokens.add(new Token(types.get(i-1), value, st, m.start(i)));
+ position = m.end(i);
+ continue OUTER;
+ }
+ }
+ throw new RuntimeException("no group matched");
+ }
+ else
+ {
+ throw new LexError("unrecognized characters line:" + LineInfo.get(st, position));
+ }
+ }
+
+ tokens.add(new Token(eof, null, st, position));
+
+ return tokens;
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexicon.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexicon.java
new file mode 100644
index 0000000000..9ab610f37a
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Lexicon.java
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+
+/**
+ * Lexicon
+ *
+ */
+
+public class Lexicon
+{
+
+ private List<Token.Type> types;
+ private Token.Type eof;
+
+ public Lexicon()
+ {
+ this.types = new ArrayList<Token.Type>();
+ this.eof = null;
+ }
+
+ public Token.Type define(String name, String pattern)
+ {
+ Token.Type t = new Token.Type(name, pattern);
+ types.add(t);
+ return t;
+ }
+
+ public Token.Type eof(String name)
+ {
+ Token.Type t = new Token.Type(name, null);
+ eof = t;
+ return t;
+ }
+
+ public Lexer compile()
+ {
+ StringBuilder joined = new StringBuilder();
+ for (Token.Type t : types)
+ {
+ if (joined.length() > 0)
+ {
+ joined.append('|');
+ }
+ joined.append('(').append(t.getPattern()).append(')');
+ }
+ Pattern rexp = Pattern.compile(joined.toString());
+ return new Lexer(new ArrayList<Token.Type>(types), eof, rexp);
+ }
+
+ public static final void main(String[] args)
+ {
+ StringBuilder input = new StringBuilder();
+ for (String a : args)
+ {
+ if (input.length() > 0)
+ {
+ input.append(" ");
+ }
+
+ input.append(a);
+ }
+
+ Lexicon lxi = new Lexicon();
+ lxi.define("FOR", "for");
+ lxi.define("IF", "if");
+ lxi.define("LPAREN", "\\(");
+ lxi.define("RPAREN", "\\)");
+ lxi.define("ID", "[\\S]+");
+ lxi.define("WSPACE", "[\\s]+");
+ lxi.eof("EOF");
+ Lexer lx = lxi.compile();
+
+ for (Token t : lx.lex(input.toString()))
+ {
+ System.out.println(t);
+ }
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LineInfo.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LineInfo.java
new file mode 100644
index 0000000000..4952fc38a3
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/LineInfo.java
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+
+/**
+ * LineInfo
+ *
+ */
+
+public class LineInfo
+{
+
+ public static LineInfo get(String st, int position)
+ {
+ int idx = 0;
+ int line = 1;
+ int column = 0;
+ int line_pos = 0;
+ while (idx < position)
+ {
+ if (st.charAt(idx) == '\n')
+ {
+ line += 1;
+ column = 0;
+ line_pos = idx;
+ }
+
+ column += 1;
+ idx += 1;
+ }
+
+ int end = st.indexOf('\n', line_pos);
+ if (end < 0)
+ {
+ end = st.length();
+ }
+
+ String text = st.substring(line_pos, end);
+
+ return new LineInfo(line, column, text);
+ }
+
+ private int line;
+ private int column;
+ private String text;
+
+ public LineInfo(int line, int column, String text)
+ {
+ this.line = line;
+ this.column = column;
+ this.text = text;
+ }
+
+ public int getLine()
+ {
+ return line;
+ }
+
+ public int getColumn()
+ {
+ return column;
+ }
+
+ public String getText()
+ {
+ return text;
+ }
+
+ public String toString()
+ {
+ return String.format("%s,%s:%s", line, column, text);
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/ParseError.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/ParseError.java
new file mode 100644
index 0000000000..ce758e15fa
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/ParseError.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import org.apache.qpid.util.Strings;
+
+
+/**
+ * ParseError
+ *
+ */
+
+public class ParseError extends RuntimeException
+{
+
+ private static String msg(Token token, Token.Type ... expected)
+ {
+ LineInfo li = token.getLineInfo();
+ String exp = Strings.join(", ", expected);
+ if (expected.length > 1)
+ {
+ exp = String.format("(%s)", exp);
+ }
+
+ if (expected.length > 0)
+ {
+ return String.format("expecting %s, got %s line:%s", exp, token, li);
+ }
+ else
+ {
+ return String.format("unexpected token %s line:%s", token, li);
+ }
+ }
+
+ public ParseError(Token token, Token.Type ... expected)
+ {
+ super(msg(token, expected));
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java
new file mode 100644
index 0000000000..2e983f5165
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Parser.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Parser
+ *
+ */
+
+class Parser
+{
+
+ private List<Token> tokens;
+ private int idx = 0;
+
+ Parser(List<Token> tokens)
+ {
+ this.tokens = tokens;
+ this.idx = 0;
+ }
+
+ Token next()
+ {
+ return tokens.get(idx);
+ }
+
+ boolean matches(Token.Type ... types)
+ {
+ for (Token.Type t : types)
+ {
+ if (next().getType() == t)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Token eat(Token.Type ... types)
+ {
+ if (types.length > 0 && !matches(types))
+ {
+ throw new ParseError(next(), types);
+ }
+ else
+ {
+ Token t = next();
+ idx += 1;
+ return t;
+ }
+ }
+
+ List<Token> eat_until(Token.Type ... types)
+ {
+ List<Token> result = new ArrayList();
+ while (!matches(types))
+ {
+ result.add(eat());
+ }
+ return result;
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/PyPrint.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/PyPrint.java
new file mode 100644
index 0000000000..ef6c724371
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/PyPrint.java
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * PyPrint
+ *
+ */
+
+public class PyPrint
+{
+
+ public static String pprint(Object obj)
+ {
+ if (obj instanceof Map)
+ {
+ return pprint_map((Map) obj);
+ }
+ else if (obj instanceof List)
+ {
+ return pprint_list((List) obj);
+ }
+ else if (obj instanceof String)
+ {
+ return pprint_string((String) obj);
+ }
+ else if (obj instanceof Boolean)
+ {
+ return ((Boolean) obj).booleanValue() ? "True" : "False";
+ }
+ else if (obj == null)
+ {
+ return "None";
+ }
+ else
+ {
+ return obj.toString();
+ }
+ }
+
+ private static String indent(String st)
+ {
+ return " " + st.replace("\n", "\n ");
+ }
+
+ private static String pprint_map(Map<Object,Object> map)
+ {
+ List<String> items = new ArrayList<String>();
+ for (Map.Entry me : map.entrySet())
+ {
+ items.add(String.format("%s: %s", pprint(me.getKey()),
+ pprint(me.getValue())));
+ }
+ Collections.sort(items);
+ return pprint_items("{", items, "}");
+ }
+
+ private static String pprint_list(List list)
+ {
+ List<String> items = new ArrayList<String>();
+ for (Object o : list)
+ {
+ items.add(pprint(o));
+ }
+ return pprint_items("[", items, "]");
+ }
+
+ private static String pprint_items(String start, List<String> items,
+ String end)
+ {
+ StringBuilder result = new StringBuilder();
+ for (String item : items)
+ {
+ if (result.length() > 0)
+ {
+ result.append(",\n");
+ }
+ result.append(indent(item));
+ }
+
+ if (result.length() > 0)
+ {
+ return String.format("%s\n%s\n%s", start, result, end);
+ }
+ else
+ {
+ return String.format("%s%s", start, end);
+ }
+ }
+
+ private static String pprint_string(String st)
+ {
+ StringBuilder result = new StringBuilder();
+ result.append('\'');
+ for (int i = 0; i < st.length(); i++)
+ {
+ char c = st.charAt(i);
+ switch (c)
+ {
+ case '\'':
+ result.append("\\'");
+ break;
+ case '\n':
+ result.append("\\n");
+ break;
+ default:
+ if (c >= 0x80)
+ {
+ result.append(String.format("\\u%04x", (int)c));
+ }
+ else
+ {
+ result.append(c);
+ }
+ break;
+ }
+ }
+ result.append('\'');
+ return result.toString();
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Token.java b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Token.java
new file mode 100644
index 0000000000..b9458d7997
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/messaging/util/Token.java
@@ -0,0 +1,106 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.messaging.util;
+
+
+/**
+ * Token
+ *
+ */
+
+public class Token
+{
+
+ public static class Type
+ {
+
+ private String name;
+ private String pattern;
+
+ Type(String name, String pattern)
+ {
+ this.name = name;
+ this.pattern = pattern;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getPattern()
+ {
+ return pattern;
+ }
+
+ public String toString()
+ {
+ return name;
+ }
+
+ }
+
+ private Type type;
+ private String value;
+ private String input;
+ private int position;
+
+ Token(Type type, String value, String input, int position)
+ {
+ this.type = type;
+ this.value = value;
+ this.input = input;
+ this.position = position;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public int getPosition()
+ {
+ return position;
+ }
+
+ public LineInfo getLineInfo()
+ {
+ return LineInfo.get(input, position);
+ }
+
+ public String toString()
+ {
+ if (value == null)
+ {
+ return type.toString();
+ }
+ else
+ {
+ return String.format("%s(%s)", type, value);
+ }
+ }
+
+}