From bf16fffe49f8ca112aacde4c335d202ada66682a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20K=C3=B6rner?= Date: Thu, 3 Jul 2025 13:44:32 +0200 Subject: [PATCH] Improve whitespaces/indentation --- .../java/org/z3950/zing/cql/CQLAndNode.java | 17 +- .../java/org/z3950/zing/cql/CQLBoolean.java | 16 +- .../org/z3950/zing/cql/CQLBooleanNode.java | 42 +- .../z3950/zing/cql/CQLDefaultNodeVisitor.java | 58 +- .../java/org/z3950/zing/cql/CQLGenerator.java | 234 +++---- .../java/org/z3950/zing/cql/CQLLexer.java | 354 +++++------ src/main/java/org/z3950/zing/cql/CQLNode.java | 72 +-- .../org/z3950/zing/cql/CQLNodeVisitor.java | 30 +- .../java/org/z3950/zing/cql/CQLNotNode.java | 16 +- .../java/org/z3950/zing/cql/CQLOrNode.java | 14 +- .../org/z3950/zing/cql/CQLParseException.java | 8 +- .../java/org/z3950/zing/cql/CQLParser.java | 582 +++++++++--------- .../java/org/z3950/zing/cql/CQLPrefix.java | 6 +- .../org/z3950/zing/cql/CQLPrefixNode.java | 46 +- .../java/org/z3950/zing/cql/CQLProxNode.java | 170 ++--- .../java/org/z3950/zing/cql/CQLRelation.java | 24 +- .../java/org/z3950/zing/cql/CQLSortNode.java | 48 +- .../java/org/z3950/zing/cql/CQLTermNode.java | 474 +++++++------- .../java/org/z3950/zing/cql/CQLTokenizer.java | 98 +-- .../zing/cql/MissingParameterException.java | 2 +- .../java/org/z3950/zing/cql/Modifier.java | 34 +- .../java/org/z3950/zing/cql/ModifierSet.java | 76 +-- .../zing/cql/PQFTranslationException.java | 2 +- .../zing/cql/UnknownPositionException.java | 2 +- .../zing/cql/UnknownRelationException.java | 2 +- .../cql/UnknownRelationModifierException.java | 2 +- .../zing/cql/UnknownTruncationException.java | 20 +- .../java/org/z3950/zing/cql/XCQLBuilder.java | 70 +-- .../z3950/zing/cql/CQLNodeVisitorTest.java | 216 +++---- .../org/z3950/zing/cql/CQLParserTest.java | 304 ++++----- 30 files changed, 1519 insertions(+), 1520 deletions(-) diff --git a/src/main/java/org/z3950/zing/cql/CQLAndNode.java b/src/main/java/org/z3950/zing/cql/CQLAndNode.java index ecff58d..2143972 100644 --- a/src/main/java/org/z3950/zing/cql/CQLAndNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLAndNode.java @@ -1,6 +1,5 @@ package org.z3950.zing.cql; - /** * Represents an AND node in a CQL parse-tree. * @@ -18,17 +17,17 @@ public class CQLAndNode extends CQLBooleanNode { * @see CQLBooleanNode */ public CQLAndNode(CQLNode left, CQLNode right, ModifierSet ms) { - super(left, right, ms, CQLBoolean.AND); - } + super(left, right, ms, CQLBoolean.AND); + } // ### Too much code duplication here with OR and NOT @Override byte[] opType1() { - byte[] op = new byte[5]; - putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator - putLen(2, op, 2); - putTag(CONTEXT, 0, PRIMITIVE, op, 3); // and - putLen(0, op, 4); - return op; + byte[] op = new byte[5]; + putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator + putLen(2, op, 2); + putTag(CONTEXT, 0, PRIMITIVE, op, 3); // and + putLen(0, op, 4); + return op; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLBoolean.java b/src/main/java/org/z3950/zing/cql/CQLBoolean.java index bab541b..37dad7e 100644 --- a/src/main/java/org/z3950/zing/cql/CQLBoolean.java +++ b/src/main/java/org/z3950/zing/cql/CQLBoolean.java @@ -5,12 +5,12 @@ * @author jakub */ public enum CQLBoolean { - /** AND is the same as CQL's "and" */ - AND, - /** OR is the same as CQL's "or" */ - OR, - /** NOT is the same as CQL's "not" */ - NOT, - /** PROX is the same as CQL's "prox" */ - PROX; + /** AND is the same as CQL's "and" */ + AND, + /** OR is the same as CQL's "or" */ + OR, + /** NOT is the same as CQL's "not" */ + NOT, + /** PROX is the same as CQL's "prox" */ + PROX; } diff --git a/src/main/java/org/z3950/zing/cql/CQLBooleanNode.java b/src/main/java/org/z3950/zing/cql/CQLBooleanNode.java index 6d903bf..c68bd14 100644 --- a/src/main/java/org/z3950/zing/cql/CQLBooleanNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLBooleanNode.java @@ -13,7 +13,7 @@ public abstract class CQLBooleanNode extends CQLNode { public CQLBoolean getOperator() { return operator; } - + private CQLNode left; /** @@ -45,25 +45,25 @@ public List getModifiers() { } protected CQLBooleanNode(CQLNode left, CQLNode right, ModifierSet ms, CQLBoolean operator) { - this.left = left; - this.right = right; - this.ms = ms; + this.left = left; + this.right = right; + this.ms = ms; this.operator = operator; } @Override public void traverse(CQLNodeVisitor visitor) { - visitor.onBooleanNodeStart(this); - left.traverse(visitor); - visitor.onBooleanNodeOp(this); - right.traverse(visitor); - visitor.onBooleanNodeEnd(this); + visitor.onBooleanNodeStart(this); + left.traverse(visitor); + visitor.onBooleanNodeOp(this); + right.traverse(visitor); + visitor.onBooleanNodeEnd(this); } @Override void toXCQLInternal(XCQLBuilder b, int level, - List prefixes, List sortkeys) { - b.indent(level).append("\n"); + List prefixes, List sortkeys) { + b.indent(level).append("\n"); renderPrefixes(b, level + 1, prefixes); ms.toXCQLInternal(b, level + 1, "boolean", "value"); b.indent(level + 1).append("\n"); @@ -78,17 +78,17 @@ void toXCQLInternal(XCQLBuilder b, int level, @Override public String toCQL() { - // ### We don't always need parens around the operands - return ("(" + left.toCQL() + ")" + - " " + ms.toCQL() + " " + - "(" + right.toCQL() + ")"); + // ### We don't always need parens around the operands + return ("(" + left.toCQL() + ")" + + " " + ms.toCQL() + " " + + "(" + right.toCQL() + ")"); } @Override public String toPQF(Properties config) throws PQFTranslationException { - return ("@" + opPQF() + - " " + left.toPQF(config) + - " " + right.toPQF(config)); + return ("@" + opPQF() + + " " + left.toPQF(config) + + " " + right.toPQF(config)); } // represents the operation for PQF: overridden for CQLProxNode @@ -97,13 +97,13 @@ public String toPQF(Properties config) throws PQFTranslationException { @Override public byte[] toType1BER(Properties config) throws PQFTranslationException { System.out.println("in CQLBooleanNode.toType1BER(): PQF=" + - toPQF(config)); + toPQF(config)); byte[] rpn1 = left.toType1BER(config); byte[] rpn2 = right.toType1BER(config); byte[] op = opType1(); byte[] rpnStructure = new byte[rpn1.length+rpn2.length+op.length+4]; - - // rpnRpnOp + + // rpnRpnOp int offset = putTag(CONTEXT, 1, CONSTRUCTED, rpnStructure, 0); rpnStructure[offset++] = (byte)(0x80&0xff); // indefinite length diff --git a/src/main/java/org/z3950/zing/cql/CQLDefaultNodeVisitor.java b/src/main/java/org/z3950/zing/cql/CQLDefaultNodeVisitor.java index 9c0b744..2598938 100644 --- a/src/main/java/org/z3950/zing/cql/CQLDefaultNodeVisitor.java +++ b/src/main/java/org/z3950/zing/cql/CQLDefaultNodeVisitor.java @@ -5,33 +5,33 @@ * @author jakub */ public class CQLDefaultNodeVisitor implements CQLNodeVisitor { - - @Override - public void onSortNode(CQLSortNode node) { - } - - @Override - public void onPrefixNode(CQLPrefixNode node) { - } - - @Override - public void onBooleanNodeStart(CQLBooleanNode node) { - } - - @Override - public void onBooleanNodeOp(CQLBooleanNode node) { - } - - @Override - public void onBooleanNodeEnd(CQLBooleanNode node) { - } - - @Override - public void onTermNode(CQLTermNode node) { - } - - @Override - public void onRelation(CQLRelation relation) { - } - + + @Override + public void onSortNode(CQLSortNode node) { + } + + @Override + public void onPrefixNode(CQLPrefixNode node) { + } + + @Override + public void onBooleanNodeStart(CQLBooleanNode node) { + } + + @Override + public void onBooleanNodeOp(CQLBooleanNode node) { + } + + @Override + public void onBooleanNodeEnd(CQLBooleanNode node) { + } + + @Override + public void onTermNode(CQLTermNode node) { + } + + @Override + public void onRelation(CQLRelation relation) { + } + } diff --git a/src/main/java/org/z3950/zing/cql/CQLGenerator.java b/src/main/java/org/z3950/zing/cql/CQLGenerator.java index 2f21563..bd53863 100644 --- a/src/main/java/org/z3950/zing/cql/CQLGenerator.java +++ b/src/main/java/org/z3950/zing/cql/CQLGenerator.java @@ -88,20 +88,20 @@ public class CQLGenerator { * */ public CQLGenerator(Properties params) { - this.params = params; - String seed = params.getProperty("seed"); - if (seed != null) - rnd = new Random(new Long(seed).longValue()); - else - rnd = new Random(); + this.params = params; + String seed = params.getProperty("seed"); + if (seed != null) + rnd = new Random(new Long(seed).longValue()); + else + rnd = new Random(); } private static void debug(String str) { - if (DEBUG) - System.err.println("DEBUG: " + str); + if (DEBUG) + System.err.println("DEBUG: " + str); } - /** + /** * Generates a single random CQL query. *

* Uses the parameters that were associated with the generator @@ -116,135 +116,135 @@ private static void debug(String str) { * method. */ public CQLNode generate() throws MissingParameterException { - return generate_cql_query(); + return generate_cql_query(); } private CQLNode generate_cql_query() throws MissingParameterException { - if (!maybe("complexQuery")) { - return generate_search_clause(); - } + if (!maybe("complexQuery")) { + return generate_search_clause(); + } - CQLNode node1 = generate_cql_query(); - CQLNode node2 = generate_search_clause(); - // ### should generate prefix-mapping nodes - if (maybe("proxOp")) { - // ### generate proximity nodes - } else { - switch (rnd.nextInt(3)) { - case 0: return new CQLAndNode(node1, node2, new ModifierSet("and")); - case 1: return new CQLOrNode (node1, node2, new ModifierSet("or")); - case 2: return new CQLNotNode(node1, node2, new ModifierSet("not")); - } - } + CQLNode node1 = generate_cql_query(); + CQLNode node2 = generate_search_clause(); + // ### should generate prefix-mapping nodes + if (maybe("proxOp")) { + // ### generate proximity nodes + } else { + switch (rnd.nextInt(3)) { + case 0: return new CQLAndNode(node1, node2, new ModifierSet("and")); + case 1: return new CQLOrNode (node1, node2, new ModifierSet("or")); + case 2: return new CQLNotNode(node1, node2, new ModifierSet("not")); + } + } - return generate_search_clause(); + return generate_search_clause(); } private CQLNode generate_search_clause() throws MissingParameterException { - if (maybe("complexClause")) { - return generate_cql_query(); - } + if (maybe("complexClause")) { + return generate_cql_query(); + } - // ### Should sometimes generate index/relation-free terms - String index = generate_index(); - CQLRelation relation = generate_relation(); - String term = generate_term(); + // ### Should sometimes generate index/relation-free terms + String index = generate_index(); + CQLRelation relation = generate_relation(); + String term = generate_term(); - return new CQLTermNode(index, relation, term); + return new CQLTermNode(index, relation, term); } // ### Should probably be more configurable private String generate_index() { - String index = ""; // shut up compiler warning - if (rnd.nextInt(2) == 0) { - switch (rnd.nextInt(3)) { - case 0: index = "dc.author"; break; - case 1: index = "dc.title"; break; - case 2: index = "dc.subject"; break; - } - } else { - switch (rnd.nextInt(4)) { - case 0: index = "bath.author"; break; - case 1: index = "bath.title"; break; - case 2: index = "bath.subject"; break; - case 3: index = "foo>bar"; break; - } - } + String index = ""; // shut up compiler warning + if (rnd.nextInt(2) == 0) { + switch (rnd.nextInt(3)) { + case 0: index = "dc.author"; break; + case 1: index = "dc.title"; break; + case 2: index = "dc.subject"; break; + } + } else { + switch (rnd.nextInt(4)) { + case 0: index = "bath.author"; break; + case 1: index = "bath.title"; break; + case 2: index = "bath.subject"; break; + case 3: index = "foo>bar"; break; + } + } - return index; + return index; } private CQLRelation generate_relation() throws MissingParameterException { - String base = generate_base_relation(); - CQLRelation rel = new CQLRelation(base); - // ### should generate modifiers too - return rel; + String base = generate_base_relation(); + CQLRelation rel = new CQLRelation(base); + // ### should generate modifiers too + return rel; } private String generate_base_relation() throws MissingParameterException { - if (maybe("equalsRelation")) { - return "="; - } else if (maybe("numericRelation")) { - return generate_numeric_relation(); - } else { - switch (rnd.nextInt(3)) { - case 0: return "within"; - case 1: return "all"; - case 2: return "any"; - } - } + if (maybe("equalsRelation")) { + return "="; + } else if (maybe("numericRelation")) { + return generate_numeric_relation(); + } else { + switch (rnd.nextInt(3)) { + case 0: return "within"; + case 1: return "all"; + case 2: return "any"; + } + } - // NOTREACHED - return ""; // shut up compiler warning + // NOTREACHED + return ""; // shut up compiler warning } // ### could read candidate terms from /usr/dict/words // ### should introduce wildcard characters // ### should generate multi-word terms private String generate_term() { - switch (rnd.nextInt(10)) { - case 0: return "cat"; - case 1: return "\"cat\""; - case 2: return "comp.os.linux"; - case 3: return "xml:element"; - case 4: return ""; - case 5: return "prox/word/>=/5"; - case 6: return ""; - case 7: return "frog fish"; - case 8: return "the complete dinosaur"; - case 9: return "foo*bar"; - } + switch (rnd.nextInt(10)) { + case 0: return "cat"; + case 1: return "\"cat\""; + case 2: return "comp.os.linux"; + case 3: return "xml:element"; + case 4: return ""; + case 5: return "prox/word/>=/5"; + case 6: return ""; + case 7: return "frog fish"; + case 8: return "the complete dinosaur"; + case 9: return "foo*bar"; + } - // NOTREACHED - return ""; // shut up compiler warning + // NOTREACHED + return ""; // shut up compiler warning } private String generate_numeric_relation() { - switch (rnd.nextInt(6)) { - case 0: return "<"; - case 1: return ">"; - case 2: return "<="; - case 3: return ">="; - case 4: return "<>"; - case 5: return "="; - } + switch (rnd.nextInt(6)) { + case 0: return "<"; + case 1: return ">"; + case 2: return "<="; + case 3: return ">="; + case 4: return "<>"; + case 5: return "="; + } - // NOTREACHED - return ""; // shut up compiler warning + // NOTREACHED + return ""; // shut up compiler warning } boolean maybe(String param) throws MissingParameterException { - String probability = params.getProperty(param); - if (probability == null) - throw new MissingParameterException(param); + String probability = params.getProperty(param); + if (probability == null) + throw new MissingParameterException(param); - double dice = rnd.nextDouble(); - double threshhold = new Double(probability).doubleValue(); - boolean res = dice < threshhold; - debug("dice=" + String.valueOf(dice).substring(0, 8) + - " vs. " + threshhold + "='" + param + "': " + res); - return res; - } + double dice = rnd.nextDouble(); + double threshhold = new Double(probability).doubleValue(); + boolean res = dice < threshhold; + debug("dice=" + String.valueOf(dice).substring(0, 8) + + " vs. " + threshhold + "='" + param + "': " + res); + return res; + } /** @@ -283,22 +283,22 @@ boolean maybe(String param) throws MissingParameterException { * to all conformant CQL compilers. */ public static void main (String[] args) throws Exception { - if (args.length % 2 != 1) { - System.err.println("Usage: CQLGenerator "+ - "[ ]..."); - System.exit(1); - } + if (args.length % 2 != 1) { + System.err.println("Usage: CQLGenerator "+ + "[ ]..."); + System.exit(1); + } + + String configFile = args[0]; + InputStream f = new FileInputStream(configFile); + Properties params = new Properties(); + params.load(f); + f.close(); + for (int i = 1; i < args.length; i += 2) + params.setProperty(args[i], args[i+1]); - String configFile = args[0]; - InputStream f = new FileInputStream(configFile); - Properties params = new Properties(); - params.load(f); - f.close(); - for (int i = 1; i < args.length; i += 2) - params.setProperty(args[i], args[i+1]); - - CQLGenerator generator = new CQLGenerator(params); - CQLNode tree = generator.generate(); - System.out.println(tree.toCQL()); + CQLGenerator generator = new CQLGenerator(params); + CQLNode tree = generator.generate(); + System.out.println(tree.toCQL()); } } diff --git a/src/main/java/org/z3950/zing/cql/CQLLexer.java b/src/main/java/org/z3950/zing/cql/CQLLexer.java index 4294b6f..216ff26 100644 --- a/src/main/java/org/z3950/zing/cql/CQLLexer.java +++ b/src/main/java/org/z3950/zing/cql/CQLLexer.java @@ -9,198 +9,198 @@ * @author jakub */ public class CQLLexer implements CQLTokenizer { - private String qs; - private int qi; - private int ql; - private int what = TT_NOTHING; - private String val; - private String lval; - private StringBuilder buf = new StringBuilder(); + private String qs; + private int qi; + private int ql; + private int what = TT_NOTHING; + private String val; + private String lval; + private StringBuilder buf = new StringBuilder(); - public CQLLexer(String cql, boolean debug) { - qs = cql; - ql = cql.length(); - } - - @Override - public void move() { - //eat whitespace - while (qi < ql && strchr(" \t\r\n", qs.charAt(qi))) - qi++; - //eof - if (qi == ql) { - what = TT_EOF; - return; + public CQLLexer(String cql, boolean debug) { + qs = cql; + ql = cql.length(); } - //current char - char c = qs.charAt(qi); - //separators - if (strchr("()/", c)) { - what = c; - qi++; - //comparitor - } else if (strchr("<>=", c)) { - what = c; - qi++; - //two-char comparitor - if (qi < ql) { - char d = qs.charAt(qi); - String comp = String.valueOf((char) c) + String.valueOf((char) d); - if (comp.equals("==")) { - what = TT_EQEQ; - qi++; - } - else if (comp.equals("<=")) { - what = TT_LE; - qi++; - } - else if (comp.equals(">=")) { - what = TT_GE; - qi++; - } - else if (comp.equals("<>")) { - what = TT_NE; - qi++; + + @Override + public void move() { + //eat whitespace + while (qi < ql && strchr(" \t\r\n", qs.charAt(qi))) + qi++; + //eof + if (qi == ql) { + what = TT_EOF; + return; } - } - //quoted string - } else if (strchr("\"", c)) { //no single-quotes - what = TT_STRING; - //remember quote char - char mark = c; - qi++; - boolean escaped = false; - buf.setLength(0); //reset buffer - while (qi < ql) { - if (!escaped && qs.charAt(qi) == mark) //terminator - break; - if (escaped && strchr("*?^\\", qs.charAt(qi))) //no escaping for d-quote - buf.append("\\"); - if (!escaped && qs.charAt(qi) == '\\') { //escape-char - escaped = true; - qi++; - continue; + //current char + char c = qs.charAt(qi); + //separators + if (strchr("()/", c)) { + what = c; + qi++; + //comparitor + } else if (strchr("<>=", c)) { + what = c; + qi++; + //two-char comparitor + if (qi < ql) { + char d = qs.charAt(qi); + String comp = String.valueOf((char) c) + String.valueOf((char) d); + if (comp.equals("==")) { + what = TT_EQEQ; + qi++; + } + else if (comp.equals("<=")) { + what = TT_LE; + qi++; + } + else if (comp.equals(">=")) { + what = TT_GE; + qi++; + } + else if (comp.equals("<>")) { + what = TT_NE; + qi++; + } + } + //quoted string + } else if (strchr("\"", c)) { //no single-quotes + what = TT_STRING; + //remember quote char + char mark = c; + qi++; + boolean escaped = false; + buf.setLength(0); //reset buffer + while (qi < ql) { + if (!escaped && qs.charAt(qi) == mark) //terminator + break; + if (escaped && strchr("*?^\\", qs.charAt(qi))) //no escaping for d-quote + buf.append("\\"); + if (!escaped && qs.charAt(qi) == '\\') { //escape-char + escaped = true; + qi++; + continue; + } + escaped = false; //reset escape + buf.append(qs.charAt(qi)); + qi++; + } + val = buf.toString(); + lval = val.toLowerCase(); + if (qi < ql) + qi++; + else //unterminated + what = TT_EOF; //notify error + //unquoted string + } else { + what = TT_WORD; + buf.setLength(0); //reset buffer + while (qi < ql + && !strchr("()/<>= \t\r\n", qs.charAt(qi))) { + buf.append(qs.charAt(qi)); + qi++; + } + val = buf.toString(); + lval = val.toLowerCase(); + if (lval.equals("or")) what = TT_OR; + else if (lval.equals("and")) what = TT_AND; + else if (lval.equals("not")) what = TT_NOT; + else if (lval.equals("prox")) what = TT_PROX; + else if (lval.equals("sortby")) what = TT_SORTBY; } - escaped = false; //reset escape - buf.append(qs.charAt(qi)); - qi++; - } - val = buf.toString(); - lval = val.toLowerCase(); - if (qi < ql) - qi++; - else //unterminated - what = TT_EOF; //notify error - //unquoted string - } else { - what = TT_WORD; - buf.setLength(0); //reset buffer - while (qi < ql - && !strchr("()/<>= \t\r\n", qs.charAt(qi))) { - buf.append(qs.charAt(qi)); - qi++; - } - val = buf.toString(); - lval = val.toLowerCase(); - if (lval.equals("or")) what = TT_OR; - else if (lval.equals("and")) what = TT_AND; - else if (lval.equals("not")) what = TT_NOT; - else if (lval.equals("prox")) what = TT_PROX; - else if (lval.equals("sortby")) what = TT_SORTBY; } - } - private boolean strchr(String s, char ch) { - return s.indexOf(ch) >= 0; - } + private boolean strchr(String s, char ch) { + return s.indexOf(ch) >= 0; + } - @Override - public String value() { - return val; - } + @Override + public String value() { + return val; + } - @Override - public int what() { - return what; - } + @Override + public int what() { + return what; + } - @Override - public String render() { - return render(what, true); - } + @Override + public String render() { + return render(what, true); + } - @Override - public String render(int token, boolean quoteChars) { - switch (token) { - case TT_EOF: - return "EOF"; - case TT_WORD: - return "word: '" + val + "'"; - case TT_STRING: - return "string: \"" + val + "\""; - case TT_LE: - return "<="; - case TT_GE: - return ">="; - case TT_NE: - return "<>"; - case TT_EQEQ: - return "=="; - case TT_AND: - return "and"; - case TT_NOT: - return "not"; - case TT_OR: - return "or"; - case TT_PROX: - return "prox"; - case TT_SORTBY: - return "sortby"; - default: - //a single character, such as '(' or '/' or relation - String res = String.valueOf((char) token); - if (quoteChars) - res = "'" + res + "'"; - return res; + @Override + public String render(int token, boolean quoteChars) { + switch (token) { + case TT_EOF: + return "EOF"; + case TT_WORD: + return "word: '" + val + "'"; + case TT_STRING: + return "string: \"" + val + "\""; + case TT_LE: + return "<="; + case TT_GE: + return ">="; + case TT_NE: + return "<>"; + case TT_EQEQ: + return "=="; + case TT_AND: + return "and"; + case TT_NOT: + return "not"; + case TT_OR: + return "or"; + case TT_PROX: + return "prox"; + case TT_SORTBY: + return "sortby"; + default: + //a single character, such as '(' or '/' or relation + String res = String.valueOf((char) token); + if (quoteChars) + res = "'" + res + "'"; + return res; + } } - } - @Override - public int pos() { - return qi; - } - - public static void main(String[] args) throws Exception { - if (args.length > 1) { - System.err.println("Usage: CQLLexer []"); - System.err.println("If unspecified, query is read from stdin"); - System.exit(1); + @Override + public int pos() { + return qi; } - String cql; - if (args.length == 1) { - cql = args[0]; - } else { - BufferedReader buff = new BufferedReader(new InputStreamReader(System.in)); - try { - // read a single line of input - cql = buff.readLine(); - if (cql == null) { - System.err.println("Can't read query from stdin"); - System.exit(2); - return; + public static void main(String[] args) throws Exception { + if (args.length > 1) { + System.err.println("Usage: CQLLexer []"); + System.err.println("If unspecified, query is read from stdin"); + System.exit(1); } - } catch (IOException ex) { - System.err.println("Can't read query: " + ex.getMessage()); - System.exit(2); - return; - } - } - CQLTokenizer lexer = new CQLLexer(cql, true); - while ((lexer.what()) != TT_EOF) { - lexer.move(); - System.out.println(lexer.render()); + String cql; + if (args.length == 1) { + cql = args[0]; + } else { + BufferedReader buff = new BufferedReader(new InputStreamReader(System.in)); + try { + // read a single line of input + cql = buff.readLine(); + if (cql == null) { + System.err.println("Can't read query from stdin"); + System.exit(2); + return; + } + } catch (IOException ex) { + System.err.println("Can't read query: " + ex.getMessage()); + System.exit(2); + return; + } + } + + CQLTokenizer lexer = new CQLLexer(cql, true); + while ((lexer.what()) != TT_EOF) { + lexer.move(); + System.out.println(lexer.render()); + } } - } } diff --git a/src/main/java/org/z3950/zing/cql/CQLNode.java b/src/main/java/org/z3950/zing/cql/CQLNode.java index b71ba1b..638bdcd 100644 --- a/src/main/java/org/z3950/zing/cql/CQLNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLNode.java @@ -10,7 +10,7 @@ * */ public abstract class CQLNode { - + public abstract void traverse(CQLNodeVisitor visitor); /** @@ -22,7 +22,7 @@ public abstract class CQLNode { * @return the name of the referenced result-set */ public String getResultSetName() { - return null; + return null; } /** @@ -33,7 +33,7 @@ public String getResultSetName() { */ public String toXCQL() { StringBuilder sb = new StringBuilder(); - toXCQLInternal(new XCQLBuilder(sb), 0); + toXCQLInternal(new XCQLBuilder(sb), 0); return sb.toString(); } @@ -42,36 +42,36 @@ void toXCQLInternal(XCQLBuilder b, int level) { } abstract void toXCQLInternal(XCQLBuilder b, int level, - List prefixes, List sortkeys); + List prefixes, List sortkeys); static void renderPrefixes(XCQLBuilder b, int level, List prefixes) { - if (prefixes == null || prefixes.size() == 0) - return; - b.indent(level).append("\n"); - for (int i = 0; i < prefixes.size(); i++) { - CQLPrefix p = prefixes.get(i); - b.indent(level+1).append("\n"); - if (p.name != null) - b.indent(level + 2).append(""). + if (prefixes == null || prefixes.size() == 0) + return; + b.indent(level).append("\n"); + for (int i = 0; i < prefixes.size(); i++) { + CQLPrefix p = prefixes.get(i); + b.indent(level+1).append("\n"); + if (p.name != null) + b.indent(level + 2).append(""). append(p.name).append("\n"); b.indent(level + 2).append(""). append(p.identifier).append("\n"); b.indent(level+1).append("\n"); - } - b.indent(level).append("\n"); + } + b.indent(level).append("\n"); } static void renderSortKeys(XCQLBuilder b, int level, - List sortkeys) { - if (sortkeys == null || sortkeys.size() == 0) - return; - b.indent(level).append("\n"); - for (int i = 0; i < sortkeys.size(); i++) { - ModifierSet key = sortkeys.get(i); - key.toXCQLInternal(b, level+1, "key", "index"); - } - b.indent(level).append("\n"); + List sortkeys) { + if (sortkeys == null || sortkeys.size() == 0) + return; + b.indent(level).append("\n"); + for (int i = 0; i < sortkeys.size(); i++) { + ModifierSet key = sortkeys.get(i); + key.toXCQLInternal(b, level+1, "key", "index"); + } + b.indent(level).append("\n"); } /** @@ -108,7 +108,7 @@ static void renderSortKeys(XCQLBuilder b, int level, * PQF configuration. */ abstract public String toPQF(Properties config) - throws PQFTranslationException; + throws PQFTranslationException; /** * Renders a parser-tree into a BER-endoded packet representing an @@ -134,7 +134,7 @@ abstract public String toPQF(Properties config) * PQF configuration. */ abstract public byte[] toType1BER(Properties config) - throws PQFTranslationException; + throws PQFTranslationException; // ANS.1 classes protected static final int UNIVERSAL = 0; @@ -162,7 +162,7 @@ abstract public byte[] toType1BER(Properties config) public static final byte GENERALSTRING = 27; protected static final int putTag(int asn1class, int fldid, int form, - byte[] record, int offset) { + byte[] record, int offset) { if (fldid < 31) record[offset++] = (byte)(fldid + asn1class*64 + form*32); else { @@ -208,7 +208,7 @@ static final int putLen(int len, byte[] record, int offset) { * @return length needed to encode given length */ protected // ### shouldn't this be private? - static final int lenLen(int length) { + static final int lenLen(int length) { return ((length < 128) ? 1 : (length < 256) ? 2 : @@ -223,8 +223,8 @@ static final int lenLen(int length) { */ protected static final int numLen(long num) { num = num < 0 ? -num : num; - // ### Wouldn't this be better done algorithmically? - // Or at least with the constants expressed in hex? + // ### Wouldn't this be better done algorithmically? + // Or at least with the constants expressed in hex? return ((num < 128) ? 1 : (num < 32768) ? 2 : (num < 8388608) ? 3 : @@ -254,7 +254,7 @@ protected static final int putNum(long num, byte record[], int offset) { // Used only by the makeOID() method private static final Map madeOIDs = - new HashMap(10); + new HashMap(10); protected static final byte[] makeOID(String oid) { byte[] o; @@ -263,7 +263,7 @@ protected static final byte[] makeOID(String oid) { if ((o = (byte[])madeOIDs.get(oid)) == null) { o = new byte[100]; - // Isn't this kind of thing excruciating in Java? + // Isn't this kind of thing excruciating in Java? while (oidOffset < oid.length() && Character.isDigit(oid.charAt(oidOffset)) == true) { if (offset > 90) // too large @@ -284,7 +284,7 @@ protected static final byte[] makeOID(String oid) { if (dot == -1) dot = oid.length(); - // ### Eh?! + // ### Eh?! value = value * 40 + Integer.parseInt(oid.substring(oidOffset,dot)); } @@ -305,13 +305,13 @@ protected static final byte[] makeOID(String oid) { o[offset++] = (byte)(bits[count] | 0x80); o[offset++] = bits[count]; - } + } dot = oid.indexOf('.', oidOffset); if (dot == -1) break; - oidOffset = dot+1; + oidOffset = dot+1; } byte[] ptr = new byte[offset]; @@ -323,7 +323,7 @@ protected static final byte[] makeOID(String oid) { } public static final byte[] makeQuery(CQLNode root, Properties properties) - throws PQFTranslationException { + throws PQFTranslationException { byte[] rpnStructure = root.toType1BER(properties); byte[] qry = new byte[rpnStructure.length+100]; int offset = 0; @@ -342,7 +342,7 @@ public static final byte[] makeQuery(CQLNode root, Properties properties) System.arraycopy(qry, 0, q, 0, offset); return q; } - + @Override public String toString() { return toCQL(); diff --git a/src/main/java/org/z3950/zing/cql/CQLNodeVisitor.java b/src/main/java/org/z3950/zing/cql/CQLNodeVisitor.java index bbd8452..cbc57c2 100644 --- a/src/main/java/org/z3950/zing/cql/CQLNodeVisitor.java +++ b/src/main/java/org/z3950/zing/cql/CQLNodeVisitor.java @@ -10,19 +10,19 @@ * @author jakub */ public interface CQLNodeVisitor { - - public void onSortNode(CQLSortNode node); - - public void onPrefixNode(CQLPrefixNode node); - - public void onBooleanNodeStart(CQLBooleanNode node); - - public void onBooleanNodeOp(CQLBooleanNode node); - - public void onBooleanNodeEnd(CQLBooleanNode node); - - public void onTermNode(CQLTermNode node); - - public void onRelation(CQLRelation relation); - + + public void onSortNode(CQLSortNode node); + + public void onPrefixNode(CQLPrefixNode node); + + public void onBooleanNodeStart(CQLBooleanNode node); + + public void onBooleanNodeOp(CQLBooleanNode node); + + public void onBooleanNodeEnd(CQLBooleanNode node); + + public void onTermNode(CQLTermNode node); + + public void onRelation(CQLRelation relation); + } diff --git a/src/main/java/org/z3950/zing/cql/CQLNotNode.java b/src/main/java/org/z3950/zing/cql/CQLNotNode.java index 743c1a0..970014a 100644 --- a/src/main/java/org/z3950/zing/cql/CQLNotNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLNotNode.java @@ -10,16 +10,16 @@ public class CQLNotNode extends CQLBooleanNode { * sides and modifiers. */ public CQLNotNode(CQLNode left, CQLNode right, ModifierSet ms) { - super(left, right, ms, CQLBoolean.NOT); - } + super(left, right, ms, CQLBoolean.NOT); + } @Override byte[] opType1() { - byte[] op = new byte[5]; - putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator - putLen(2, op, 2); - putTag(CONTEXT, 2, PRIMITIVE, op, 3); // and-not - putLen(0, op, 4); - return op; + byte[] op = new byte[5]; + putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator + putLen(2, op, 2); + putTag(CONTEXT, 2, PRIMITIVE, op, 3); // and-not + putLen(0, op, 4); + return op; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLOrNode.java b/src/main/java/org/z3950/zing/cql/CQLOrNode.java index 32600c6..bbe509e 100644 --- a/src/main/java/org/z3950/zing/cql/CQLOrNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLOrNode.java @@ -10,16 +10,16 @@ public class CQLOrNode extends CQLBooleanNode { * sides and modifiers. */ public CQLOrNode(CQLNode left, CQLNode right, ModifierSet ms) { - super(left, right, ms, CQLBoolean.OR); + super(left, right, ms, CQLBoolean.OR); } @Override byte[] opType1() { - byte[] op = new byte[5]; - putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator - putLen(2, op, 2); - putTag(CONTEXT, 1, PRIMITIVE, op, 3); // or - putLen(0, op, 4); - return op; + byte[] op = new byte[5]; + putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator + putLen(2, op, 2); + putTag(CONTEXT, 1, PRIMITIVE, op, 3); // or + putLen(0, op, 4); + return op; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLParseException.java b/src/main/java/org/z3950/zing/cql/CQLParseException.java index 311fa42..aa357a7 100644 --- a/src/main/java/org/z3950/zing/cql/CQLParseException.java +++ b/src/main/java/org/z3950/zing/cql/CQLParseException.java @@ -13,16 +13,16 @@ public class CQLParseException extends Exception { * usually a syntax error of some kind. */ public CQLParseException(String s, int pos) { - super(s); + super(s); this.pos = pos; } - + /** * Character position of the parsing error. - * @return + * @return */ public int getPosition() { - return pos; + return pos; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLParser.java b/src/main/java/org/z3950/zing/cql/CQLParser.java index 93c7c10..497dde7 100644 --- a/src/main/java/org/z3950/zing/cql/CQLParser.java +++ b/src/main/java/org/z3950/zing/cql/CQLParser.java @@ -21,7 +21,7 @@ public class CQLParser { private CQLTokenizer lexer; private final int compat; // When false, implement CQL 1.2 private final Set customRelations = new HashSet(); - + public static final int V1POINT1 = 12368; public static final int V1POINT2 = 12369; public static final int V1POINT1SORT = 12370; @@ -44,35 +44,35 @@ public class CQLParser { * */ public CQLParser(int compat) { - this.compat = compat; + this.compat = compat; this.allowKeywordTerms = true; } - + /** - * Official CQL grammar allows registered keywords like 'and/or/not/sortby/prox' - * to be used unquoted in terms. This constructor allows to create an instance + * Official CQL grammar allows registered keywords like 'and/or/not/sortby/prox' + * to be used unquoted in terms. This constructor allows to create an instance * of a parser that prohibits this behavior while sacrificing compatibility. * @param compat CQL version compatibility * @param allowKeywordTerms when false registered keywords are disallowed in unquoted terms */ public CQLParser(int compat, boolean allowKeywordTerms) { - this.compat = compat; + this.compat = compat; this.allowKeywordTerms = allowKeywordTerms; } - + /** * The new parser implements CQL 1.2 */ public CQLParser() { - this.compat = V1POINT2; + this.compat = V1POINT2; this.allowKeywordTerms = true; } private static void debug(String str) { - if (DEBUG) - System.err.println("PARSEDEBUG: " + str); + if (DEBUG) + System.err.println("PARSEDEBUG: " + str); } - + /** * Registers custom relation in this parser. Note that when a custom relation * is registered the parser is no longer strictly compliant with the chosen spec. @@ -80,16 +80,16 @@ private static void debug(String str) { * @return true if custom relation has not been registered already */ public boolean registerCustomRelation(String relation) { - return customRelations.add(relation); + return customRelations.add(relation); } - + /** * Unregisters previously registered custom relation in this instance of the parser. * @param relation * @return true is relation has been previously registered */ public boolean unregisterCustomRelation(String relation) { - return customRelations.remove(relation); + return customRelations.remove(relation); } /** @@ -109,188 +109,188 @@ public boolean unregisterCustomRelation(String relation) { * @return A CQLNode object which is the root of a parse * tree representing the query. */ public CQLNode parse(String cql) - throws CQLParseException, IOException { - lexer = new CQLLexer(cql, LEXDEBUG); - - lexer.move(); - debug("about to parseQuery()"); - CQLNode root = parseTopLevelPrefixes("cql.serverChoice", - new CQLRelation(compat == V1POINT2 ? "=" : "scr")); - if (lexer.what() != CQLTokenizer.TT_EOF) - throw new CQLParseException("junk after end: " + lexer.render(), - lexer.pos()); - - return root; + throws CQLParseException, IOException { + lexer = new CQLLexer(cql, LEXDEBUG); + + lexer.move(); + debug("about to parseQuery()"); + CQLNode root = parseTopLevelPrefixes("cql.serverChoice", + new CQLRelation(compat == V1POINT2 ? "=" : "scr")); + if (lexer.what() != CQLTokenizer.TT_EOF) + throw new CQLParseException("junk after end: " + lexer.render(), + lexer.pos()); + + return root; } private CQLNode parseTopLevelPrefixes(String index, CQLRelation relation) - throws CQLParseException, IOException { - debug("top-level prefix mapping"); - - if (lexer.what() == '>') { - return parsePrefix(index, relation, true); - } - - CQLNode node = parseQuery(index, relation); - if ((compat == V1POINT2 || compat == V1POINT1SORT) && - lexer.what() == CQLTokenizer.TT_SORTBY) { - match(lexer.what()); - debug("sortspec"); - - CQLSortNode sortnode = new CQLSortNode(node); - while (lexer.what() != CQLTokenizer.TT_EOF) { - String sortindex = matchSymbol("sort index"); - ModifierSet ms = gatherModifiers(sortindex); - sortnode.addSortIndex(ms); - } - - if (sortnode.keys.size() == 0) { - throw new CQLParseException("no sort keys", lexer.pos()); - } - - node = sortnode; - } - - return node; + throws CQLParseException, IOException { + debug("top-level prefix mapping"); + + if (lexer.what() == '>') { + return parsePrefix(index, relation, true); + } + + CQLNode node = parseQuery(index, relation); + if ((compat == V1POINT2 || compat == V1POINT1SORT) && + lexer.what() == CQLTokenizer.TT_SORTBY) { + match(lexer.what()); + debug("sortspec"); + + CQLSortNode sortnode = new CQLSortNode(node); + while (lexer.what() != CQLTokenizer.TT_EOF) { + String sortindex = matchSymbol("sort index"); + ModifierSet ms = gatherModifiers(sortindex); + sortnode.addSortIndex(ms); + } + + if (sortnode.keys.size() == 0) { + throw new CQLParseException("no sort keys", lexer.pos()); + } + + node = sortnode; + } + + return node; } private CQLNode parseQuery(String index, CQLRelation relation) - throws CQLParseException, IOException { - debug("in parseQuery()"); - - CQLNode term = parseTerm(index, relation); - while (lexer.what() != CQLTokenizer.TT_EOF && - lexer.what() != ')' && - lexer.what() != CQLTokenizer.TT_SORTBY) { - if (lexer.what() == CQLTokenizer.TT_AND || - lexer.what() == CQLTokenizer.TT_OR || - lexer.what() == CQLTokenizer.TT_NOT || - lexer.what() == CQLTokenizer.TT_PROX) { - int type = lexer.what(); - String val = lexer.value(); - match(type); - ModifierSet ms = gatherModifiers(val); - CQLNode term2 = parseTerm(index, relation); - term = ((type == CQLTokenizer.TT_AND) ? new CQLAndNode(term, term2, ms) : - (type == CQLTokenizer.TT_OR) ? new CQLOrNode (term, term2, ms) : - (type == CQLTokenizer.TT_NOT) ? new CQLNotNode(term, term2, ms) : - new CQLProxNode(term, term2, ms)); - } else { - throw new CQLParseException("expected boolean, got " + - lexer.render(), lexer.pos()); - } - } - - debug("no more ops"); - return term; + throws CQLParseException, IOException { + debug("in parseQuery()"); + + CQLNode term = parseTerm(index, relation); + while (lexer.what() != CQLTokenizer.TT_EOF && + lexer.what() != ')' && + lexer.what() != CQLTokenizer.TT_SORTBY) { + if (lexer.what() == CQLTokenizer.TT_AND || + lexer.what() == CQLTokenizer.TT_OR || + lexer.what() == CQLTokenizer.TT_NOT || + lexer.what() == CQLTokenizer.TT_PROX) { + int type = lexer.what(); + String val = lexer.value(); + match(type); + ModifierSet ms = gatherModifiers(val); + CQLNode term2 = parseTerm(index, relation); + term = ((type == CQLTokenizer.TT_AND) ? new CQLAndNode(term, term2, ms) : + (type == CQLTokenizer.TT_OR) ? new CQLOrNode (term, term2, ms) : + (type == CQLTokenizer.TT_NOT) ? new CQLNotNode(term, term2, ms) : + new CQLProxNode(term, term2, ms)); + } else { + throw new CQLParseException("expected boolean, got " + + lexer.render(), lexer.pos()); + } + } + + debug("no more ops"); + return term; } private ModifierSet gatherModifiers(String base) - throws CQLParseException, IOException { - debug("in gatherModifiers()"); - - ModifierSet ms = new ModifierSet(base); - while (lexer.what() == '/') { - match('/'); - if (lexer.what() != CQLTokenizer.TT_WORD) - throw new CQLParseException("expected modifier, " - + "got " + lexer.render(), - lexer.pos()); - String type = lexer.value().toLowerCase(); - match(lexer.what()); - if (!isSymbolicRelation()) { - // It's a simple modifier consisting of type only - ms.addModifier(type); - } else { - // It's a complex modifier of the form type=value - String comparision = lexer.render(lexer.what(), false); - match(lexer.what()); - String value = matchSymbol("modifier value"); - ms.addModifier(type, comparision, value); - } - } - - return ms; + throws CQLParseException, IOException { + debug("in gatherModifiers()"); + + ModifierSet ms = new ModifierSet(base); + while (lexer.what() == '/') { + match('/'); + if (lexer.what() != CQLTokenizer.TT_WORD) + throw new CQLParseException("expected modifier, " + + "got " + lexer.render(), + lexer.pos()); + String type = lexer.value().toLowerCase(); + match(lexer.what()); + if (!isSymbolicRelation()) { + // It's a simple modifier consisting of type only + ms.addModifier(type); + } else { + // It's a complex modifier of the form type=value + String comparision = lexer.render(lexer.what(), false); + match(lexer.what()); + String value = matchSymbol("modifier value"); + ms.addModifier(type, comparision, value); + } + } + + return ms; } private CQLNode parseTerm(String index, CQLRelation relation) - throws CQLParseException, IOException { - debug("in parseTerm()"); + throws CQLParseException, IOException { + debug("in parseTerm()"); - String first; + String first; StringBuilder all; - while (true) { - if (lexer.what() == '(') { - debug("parenthesised term"); - match('('); - CQLNode expr = parseQuery(index, relation); - match(')'); - return expr; - } else if (lexer.what() == '>') { - return parsePrefix(index, relation, false); - } - - debug("non-parenthesised term"); - first = matchSymbol("index or term"); + while (true) { + if (lexer.what() == '(') { + debug("parenthesised term"); + match('('); + CQLNode expr = parseQuery(index, relation); + match(')'); + return expr; + } else if (lexer.what() == '>') { + return parsePrefix(index, relation, false); + } + + debug("non-parenthesised term"); + first = matchSymbol("index or term"); all = new StringBuilder(first); //match relation only on second postion while (isWordOrString() && (all.length() > first.length() || !isRelation())) { - all.append(" ").append(lexer.value()); - match(lexer.what()); + all.append(" ").append(lexer.value()); + match(lexer.what()); } - if (!isRelation()) + if (!isRelation()) break; //we're done if no relation - + //render relation - String relstr = (lexer.what() == CQLTokenizer.TT_WORD ? - lexer.value() : lexer.render(lexer.what(), false)); + String relstr = (lexer.what() == CQLTokenizer.TT_WORD ? + lexer.value() : lexer.render(lexer.what(), false)); //we have relation, but it only makes sense if preceded by a single term if (all.length() > first.length()) { - throw new CQLParseException("unexpected relation '"+relstr+"'" - , lexer.pos()); + throw new CQLParseException("unexpected relation '"+relstr+"'", + lexer.pos()); } index = first; - relation = new CQLRelation(relstr); - match(lexer.what()); - ModifierSet ms = gatherModifiers(relstr); - relation.ms = ms; - debug("index='" + index + ", " + - "relation='" + relation.toCQL() + "'"); - } - CQLTermNode node = new CQLTermNode(index, relation, all.toString()); - debug("made term node " + node.toCQL()); - return node; + relation = new CQLRelation(relstr); + match(lexer.what()); + ModifierSet ms = gatherModifiers(relstr); + relation.ms = ms; + debug("index='" + index + ", " + + "relation='" + relation.toCQL() + "'"); + } + CQLTermNode node = new CQLTermNode(index, relation, all.toString()); + debug("made term node " + node.toCQL()); + return node; } private CQLNode parsePrefix(String index, CQLRelation relation, - boolean topLevel) - throws CQLParseException, IOException { - debug("prefix mapping"); - - match('>'); - String name = null; - String identifier = matchSymbol("prefix-name"); - if (lexer.what() == '=') { - match('='); - name = identifier; - identifier = matchSymbol("prefix-identifer"); - } - CQLNode node = topLevel ? - parseTopLevelPrefixes(index, relation) : - parseQuery(index, relation); - - return new CQLPrefixNode(name, identifier, node); + boolean topLevel) + throws CQLParseException, IOException { + debug("prefix mapping"); + + match('>'); + String name = null; + String identifier = matchSymbol("prefix-name"); + if (lexer.what() == '=') { + match('='); + name = identifier; + identifier = matchSymbol("prefix-identifer"); + } + CQLNode node = topLevel ? + parseTopLevelPrefixes(index, relation) : + parseQuery(index, relation); + + return new CQLPrefixNode(name, identifier, node); } - + private boolean isWordOrString() { - return CQLTokenizer.TT_WORD == lexer.what() + return CQLTokenizer.TT_WORD == lexer.what() || CQLTokenizer.TT_STRING == lexer.what(); } private boolean isRelation() { - debug("isRelation: checking what()=" + lexer.what() + - " (" + lexer.render() + ")"); + debug("isRelation: checking what()=" + lexer.what() + + " (" + lexer.render() + ")"); if (lexer.what() == CQLTokenizer.TT_WORD && (lexer.value().indexOf('.') >= 0 || lexer.value().equals("any") || @@ -307,51 +307,51 @@ private boolean isRelation() { } private boolean isSymbolicRelation() { - debug("isSymbolicRelation: checking what()=" + lexer.what() + - " (" + lexer.render() + ")"); - return (lexer.what() == '<' || - lexer.what() == '>' || - lexer.what() == '=' || - lexer.what() == CQLTokenizer.TT_LE || - lexer.what() == CQLTokenizer.TT_GE || - lexer.what() == CQLTokenizer.TT_NE || - lexer.what() == CQLTokenizer.TT_EQEQ); + debug("isSymbolicRelation: checking what()=" + lexer.what() + + " (" + lexer.render() + ")"); + return (lexer.what() == '<' || + lexer.what() == '>' || + lexer.what() == '=' || + lexer.what() == CQLTokenizer.TT_LE || + lexer.what() == CQLTokenizer.TT_GE || + lexer.what() == CQLTokenizer.TT_NE || + lexer.what() == CQLTokenizer.TT_EQEQ); } private void match(int token) - throws CQLParseException, IOException { - debug("in match(" + lexer.render(token, true) + ")"); - if (lexer.what() != token) - throw new CQLParseException("expected " + - lexer.render(token, true) + - ", " + "got " + lexer.render(), - lexer.pos()); - lexer.move(); - debug("match() got token=" + lexer.what() + ", value()='" + lexer.value() + "'"); + throws CQLParseException, IOException { + debug("in match(" + lexer.render(token, true) + ")"); + if (lexer.what() != token) + throw new CQLParseException("expected " + + lexer.render(token, true) + + ", " + "got " + lexer.render(), + lexer.pos()); + lexer.move(); + debug("match() got token=" + lexer.what() + ", value()='" + lexer.value() + "'"); } private String matchSymbol(String expected) - throws CQLParseException, IOException { - - debug("in matchSymbol()"); - if (lexer.what() == CQLTokenizer.TT_WORD || - lexer.what() == CQLTokenizer.TT_STRING || - // The following is a complete list of keywords. Because - // they're listed here, they can be used unquoted as - // indexes, terms, prefix names and prefix identifiers. + throws CQLParseException, IOException { + + debug("in matchSymbol()"); + if (lexer.what() == CQLTokenizer.TT_WORD || + lexer.what() == CQLTokenizer.TT_STRING || + // The following is a complete list of keywords. Because + // they're listed here, they can be used unquoted as + // indexes, terms, prefix names and prefix identifiers. (allowKeywordTerms && - lexer.what() == CQLTokenizer.TT_AND || - lexer.what() == CQLTokenizer.TT_OR || - lexer.what() == CQLTokenizer.TT_NOT || - lexer.what() == CQLTokenizer.TT_PROX || - lexer.what() == CQLTokenizer.TT_SORTBY)) { - String symbol = lexer.value(); - match(lexer.what()); - return symbol; - } - - throw new CQLParseException("expected " + expected + ", " + - "got " + lexer.render(), lexer.pos()); + lexer.what() == CQLTokenizer.TT_AND || + lexer.what() == CQLTokenizer.TT_OR || + lexer.what() == CQLTokenizer.TT_NOT || + lexer.what() == CQLTokenizer.TT_PROX || + lexer.what() == CQLTokenizer.TT_SORTBY)) { + String symbol = lexer.value(); + match(lexer.what()); + return symbol; + } + + throw new CQLParseException("expected " + expected + ", " + + "got " + lexer.render(), lexer.pos()); } @@ -414,115 +414,115 @@ private String matchSymbol(String expected) * -c option is supplied]. */ public static void main (String[] args) { - char mode = 'x'; // x=XCQL, c=CQL, p=PQF - String pfile = null; - - List argv = new ArrayList(); - for (int i = 0; i < args.length; i++) { - argv.add(args[i]); - } - - int compat = V1POINT2; - if (argv.size() > 0 && argv.get(0).equals("-1")) { - compat = V1POINT1; - argv.remove(0); - } - - if (argv.size() > 0 && argv.get(0).equals("-d")) { - DEBUG = true; - argv.remove(0); - } - - if (argv.size() > 0 && argv.get(0).equals("-c")) { - mode = 'c'; - argv.remove(0); - } else if (argv.size() > 1 && argv.get(0).equals("-p")) { - mode = 'p'; - argv.remove(0); - pfile = (String) argv.get(0); - argv.remove(0); - } - - if (argv.size() > 1) { - System.err.println("Usage: CQLParser [-1] [-d] [-c] " + - "[-p []"); - System.err.println("If unspecified, query is read from stdin"); - System.exit(1); - } - - String cql; - if (argv.size() == 1) { - cql = (String) argv.get(0); - } else { - BufferedReader buff = new BufferedReader(new InputStreamReader(System.in)); - try { - // read a single line of input + char mode = 'x'; // x=XCQL, c=CQL, p=PQF + String pfile = null; + + List argv = new ArrayList(); + for (int i = 0; i < args.length; i++) { + argv.add(args[i]); + } + + int compat = V1POINT2; + if (argv.size() > 0 && argv.get(0).equals("-1")) { + compat = V1POINT1; + argv.remove(0); + } + + if (argv.size() > 0 && argv.get(0).equals("-d")) { + DEBUG = true; + argv.remove(0); + } + + if (argv.size() > 0 && argv.get(0).equals("-c")) { + mode = 'c'; + argv.remove(0); + } else if (argv.size() > 1 && argv.get(0).equals("-p")) { + mode = 'p'; + argv.remove(0); + pfile = (String) argv.get(0); + argv.remove(0); + } + + if (argv.size() > 1) { + System.err.println("Usage: CQLParser [-1] [-d] [-c] " + + "[-p []"); + System.err.println("If unspecified, query is read from stdin"); + System.exit(1); + } + + String cql; + if (argv.size() == 1) { + cql = (String) argv.get(0); + } else { + BufferedReader buff = new BufferedReader(new InputStreamReader(System.in)); + try { + // read a single line of input cql = buff.readLine(); if (cql == null) { System.err.println("Can't read query from stdin"); - System.exit(2); + System.exit(2); return; } - } catch (IOException ex) { - System.err.println("Can't read query: " + ex.getMessage()); - System.exit(2); + } catch (IOException ex) { + System.err.println("Can't read query: " + ex.getMessage()); + System.exit(2); return; - } - } - - CQLParser parser = new CQLParser(compat); - CQLNode root; - try { - root = parser.parse(cql); - } catch (CQLParseException ex) { - System.err.println("Syntax error: " + ex.getMessage()); + } + } + + CQLParser parser = new CQLParser(compat); + CQLNode root; + try { + root = parser.parse(cql); + } catch (CQLParseException ex) { + System.err.println("Syntax error: " + ex.getMessage()); StringBuilder space = new StringBuilder(cql.length()); System.out.println(cql); for (int i=0; i prefixes, - List sortkeys) { - List tmp = (prefixes == null ? - new ArrayList() : - new ArrayList(prefixes)); - tmp.add(prefix); - subtree.toXCQLInternal(b, level, tmp, sortkeys); + List sortkeys) { + List tmp = (prefixes == null ? + new ArrayList() : + new ArrayList(prefixes)); + tmp.add(prefix); + subtree.toXCQLInternal(b, level, tmp, sortkeys); } @Override public String toCQL() { - // ### We don't always need parens around the subtree - if (prefix.name == null) { - return ">\"" + prefix.identifier + "\" " + - "(" + subtree.toCQL() + ")"; - } else { - return ">" + prefix.name + "=\"" + prefix.identifier + "\" " + - "(" + subtree.toCQL() + ")"; - } + // ### We don't always need parens around the subtree + if (prefix.name == null) { + return ">\"" + prefix.identifier + "\" " + + "(" + subtree.toCQL() + ")"; + } else { + return ">" + prefix.name + "=\"" + prefix.identifier + "\" " + + "(" + subtree.toCQL() + ")"; + } } @Override public String toPQF(Properties config) throws PQFTranslationException { - // Prefixes and their identifiers don't actually play any role - // in PQF translation, since the meanings of the indexes, - // including their prefixes if any, are instead wired into - // `config'. - return subtree.toPQF(config); + // Prefixes and their identifiers don't actually play any role + // in PQF translation, since the meanings of the indexes, + // including their prefixes if any, are instead wired into + // `config'. + return subtree.toPQF(config); } @Override public byte[] toType1BER(Properties config) throws PQFTranslationException { - // See comment on toPQF() - return subtree.toType1BER(config); + // See comment on toPQF() + return subtree.toType1BER(config); } } diff --git a/src/main/java/org/z3950/zing/cql/CQLProxNode.java b/src/main/java/org/z3950/zing/cql/CQLProxNode.java index 3e844ca..0bcaa0d 100644 --- a/src/main/java/org/z3950/zing/cql/CQLProxNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLProxNode.java @@ -13,8 +13,8 @@ public class CQLProxNode extends CQLBooleanNode { * sides and modifiers. */ public CQLProxNode(CQLNode left, CQLNode right, ModifierSet ms) { - super(left, right, ms, CQLBoolean.PROX); - } + super(left, right, ms, CQLBoolean.PROX); + } /* * proximity ::= exclusion distance ordered relation which-code unit-code. @@ -27,99 +27,99 @@ public CQLProxNode(CQLNode left, CQLNode right, ModifierSet ms) { */ @Override String opPQF() { - int relCode = getRelCode(); - int unitCode = getProxUnitCode(); - - String res = "prox " + - "0 " + - ms.modifier("distance") + " " + - (ms.modifier("ordering").equals("ordered") ? 1 : 0) + " " + - relCode + " " + - "1 " + - unitCode; - - return res; + int relCode = getRelCode(); + int unitCode = getProxUnitCode(); + + String res = "prox " + + "0 " + + ms.modifier("distance") + " " + + (ms.modifier("ordering").equals("ordered") ? 1 : 0) + " " + + relCode + " " + + "1 " + + unitCode; + + return res; } private int getRelCode() { - String rel = ms.modifier("relation"); - if (rel.equals("<")) { - return 1; - } else if (rel.equals("<=")) { - return 2; - } else if (rel.equals("=")) { - return 3; - } else if (rel.equals(">=")) { - return 4; - } else if (rel.equals(">")) { - return 5; - } else if (rel.equals("<>")) { - return 6; - } - return 0; + String rel = ms.modifier("relation"); + if (rel.equals("<")) { + return 1; + } else if (rel.equals("<=")) { + return 2; + } else if (rel.equals("=")) { + return 3; + } else if (rel.equals(">=")) { + return 4; + } else if (rel.equals(">")) { + return 5; + } else if (rel.equals("<>")) { + return 6; + } + return 0; } private int getProxUnitCode() { - String unit = ms.modifier("unit"); - if (unit.equals("word")) { - return 2; - } else if (unit.equals("sentence")) { - return 3; - } else if (unit.equals("paragraph")) { - return 4; - } else if (unit.equals("element")) { - return 8; - } - return 0; + String unit = ms.modifier("unit"); + if (unit.equals("word")) { + return 2; + } else if (unit.equals("sentence")) { + return 3; + } else if (unit.equals("paragraph")) { + return 4; + } else if (unit.equals("element")) { + return 8; + } + return 0; } @Override byte[] opType1() { - byte[] op = new byte[100]; - int offset, value; - offset = putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator - op[offset++] = (byte)(0x80&0xff); // indefinite length - - offset = putTag(CONTEXT, 3, CONSTRUCTED, op, offset); // prox - op[offset++] = (byte)(0x80&0xff); // indefinite length - - offset = putTag(CONTEXT, 1, PRIMITIVE, op, offset); // exclusion - value = 0; // false - offset = putLen(numLen(value), op, offset); - offset = putNum(value, op, offset); - - offset = putTag(CONTEXT, 2, PRIMITIVE, op, offset); // distance - value = Integer.parseInt(ms.modifier("distance")); - offset = putLen(numLen(value), op, offset); - offset = putNum(value, op, offset); - - offset = putTag(CONTEXT, 3, PRIMITIVE, op, offset); // ordered - value = ms.modifier("ordering").equals("ordered") ? 1 : 0; - offset = putLen(numLen(value), op, offset); - offset = putNum(value, op, offset); - - offset = putTag(CONTEXT, 4, PRIMITIVE, op, offset); // relationType - value = getRelCode(); - offset = putLen(numLen(value), op, offset); - offset = putNum(value, op, offset); - - offset = putTag(CONTEXT, 5, CONSTRUCTED, op, offset); // proximityUnitCode - op[offset++] = (byte)(0x80&0xff); // indefinite length - offset = putTag(CONTEXT, 1, PRIMITIVE, op, offset); // known - value = getProxUnitCode(); - offset = putLen(numLen(value), op, offset); - offset = putNum(value, op, offset); - op[offset++] = 0x00; // end of proximityUnitCode - op[offset++] = 0x00; - - op[offset++] = 0x00; // end of prox - op[offset++] = 0x00; - op[offset++] = 0x00; // end of Operator - op[offset++] = 0x00; - - byte[] o = new byte[offset]; - System.arraycopy(op, 0, o, 0, offset); - return o; + byte[] op = new byte[100]; + int offset, value; + offset = putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator + op[offset++] = (byte)(0x80&0xff); // indefinite length + + offset = putTag(CONTEXT, 3, CONSTRUCTED, op, offset); // prox + op[offset++] = (byte)(0x80&0xff); // indefinite length + + offset = putTag(CONTEXT, 1, PRIMITIVE, op, offset); // exclusion + value = 0; // false + offset = putLen(numLen(value), op, offset); + offset = putNum(value, op, offset); + + offset = putTag(CONTEXT, 2, PRIMITIVE, op, offset); // distance + value = Integer.parseInt(ms.modifier("distance")); + offset = putLen(numLen(value), op, offset); + offset = putNum(value, op, offset); + + offset = putTag(CONTEXT, 3, PRIMITIVE, op, offset); // ordered + value = ms.modifier("ordering").equals("ordered") ? 1 : 0; + offset = putLen(numLen(value), op, offset); + offset = putNum(value, op, offset); + + offset = putTag(CONTEXT, 4, PRIMITIVE, op, offset); // relationType + value = getRelCode(); + offset = putLen(numLen(value), op, offset); + offset = putNum(value, op, offset); + + offset = putTag(CONTEXT, 5, CONSTRUCTED, op, offset); // proximityUnitCode + op[offset++] = (byte)(0x80&0xff); // indefinite length + offset = putTag(CONTEXT, 1, PRIMITIVE, op, offset); // known + value = getProxUnitCode(); + offset = putLen(numLen(value), op, offset); + offset = putNum(value, op, offset); + op[offset++] = 0x00; // end of proximityUnitCode + op[offset++] = 0x00; + + op[offset++] = 0x00; // end of prox + op[offset++] = 0x00; + op[offset++] = 0x00; // end of Operator + op[offset++] = 0x00; + + byte[] o = new byte[offset]; + System.arraycopy(op, 0, o, 0, offset); + return o; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLRelation.java b/src/main/java/org/z3950/zing/cql/CQLRelation.java index 6f52eec..2f0c099 100644 --- a/src/main/java/org/z3950/zing/cql/CQLRelation.java +++ b/src/main/java/org/z3950/zing/cql/CQLRelation.java @@ -21,7 +21,7 @@ public class CQLRelation extends CQLNode { // ### Seems wrong: a modifier set should not have a base, a // relation should public CQLRelation(String base) { - ms = new ModifierSet(base); + ms = new ModifierSet(base); } /** @@ -29,7 +29,7 @@ public CQLRelation(String base) { * originally created. */ public String getBase() { - return ms.getBase(); + return ms.getBase(); } /** @@ -38,34 +38,34 @@ public String getBase() { * An array of Modifier objects. */ public List getModifiers() { - return ms.getModifiers(); + return ms.getModifiers(); } @Override public void traverse(CQLNodeVisitor visitor) { visitor.onRelation(this); - } - + } + @Override void toXCQLInternal(XCQLBuilder b, int level, List prefixes, - List sortkeys) { - if (sortkeys != null) - throw new Error("CQLRelation.toXCQL() called with sortkeys"); - ms.toXCQLInternal(b, level, "relation", "value"); + List sortkeys) { + if (sortkeys != null) + throw new Error("CQLRelation.toXCQL() called with sortkeys"); + ms.toXCQLInternal(b, level, "relation", "value"); } @Override public String toCQL() { - return ms.toCQL(); + return ms.toCQL(); } @Override public String toPQF(Properties config) throws PQFTranslationException { - throw new Error("CQLRelation.toPQF() can never be called"); + throw new Error("CQLRelation.toPQF() can never be called"); } @Override public byte[] toType1BER(Properties config) { - throw new Error("CQLRelation.toType1BER() can never be called"); + throw new Error("CQLRelation.toType1BER() can never be called"); } } diff --git a/src/main/java/org/z3950/zing/cql/CQLSortNode.java b/src/main/java/org/z3950/zing/cql/CQLSortNode.java index 9aed194..98c1bc8 100644 --- a/src/main/java/org/z3950/zing/cql/CQLSortNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLSortNode.java @@ -12,14 +12,14 @@ public class CQLSortNode extends CQLNode { /** * The root of a subtree representing the query whose result is to * be sorted. - */ + */ private CQLNode subtree; /** * The set of sort keys by which results are to be sorted, * each expressed as an index together with zero or more * modifiers. - */ + */ List keys; public CQLNode getSubtree() { @@ -27,16 +27,16 @@ public CQLNode getSubtree() { } public CQLSortNode(CQLNode subtree) { - this.subtree = subtree; - keys = new ArrayList(); + this.subtree = subtree; + keys = new ArrayList(); } public void addSortIndex(ModifierSet key) { - keys.add(key); + keys.add(key); } public List getSortIndexes() { - return keys; + return keys; } @Override @@ -47,38 +47,38 @@ public void traverse(CQLNodeVisitor visitor) { @Override void toXCQLInternal(XCQLBuilder b, int level, List prefixes, - List sortkeys) { - if (sortkeys != null) - throw new Error("CQLSortNode.toXCQL() called with sortkeys"); - subtree.toXCQLInternal(b, level, prefixes, keys); + List sortkeys) { + if (sortkeys != null) + throw new Error("CQLSortNode.toXCQL() called with sortkeys"); + subtree.toXCQLInternal(b, level, prefixes, keys); } @Override public String toCQL() { - StringBuilder buf = new StringBuilder(subtree.toCQL()); + StringBuilder buf = new StringBuilder(subtree.toCQL()); - if (keys != null) { - buf.append(" sortby"); - for (int i = 0; i < keys.size(); i++) { - ModifierSet key = keys.get(i); - buf.append(" ").append(key.toCQL()); - } - } + if (keys != null) { + buf.append(" sortby"); + for (int i = 0; i < keys.size(); i++) { + ModifierSet key = keys.get(i); + buf.append(" ").append(key.toCQL()); + } + } - return buf.toString(); + return buf.toString(); } @Override public String toPQF(Properties config) throws PQFTranslationException { - return "@attr 1=oops \"###\""; + return "@attr 1=oops \"###\""; } @Override public byte[] toType1BER(Properties config) - throws PQFTranslationException { - // There is no way to represent sorting in a standard Z39.50 - // Type-1 query, so the best we can do is return the - // underlying query and ignore the sort-specification. + throws PQFTranslationException { + // There is no way to represent sorting in a standard Z39.50 + // Type-1 query, so the best we can do is return the + // underlying query and ignore the sort-specification. return subtree.toType1BER(config); } } diff --git a/src/main/java/org/z3950/zing/cql/CQLTermNode.java b/src/main/java/org/z3950/zing/cql/CQLTermNode.java index 02a8229..47f7f38 100644 --- a/src/main/java/org/z3950/zing/cql/CQLTermNode.java +++ b/src/main/java/org/z3950/zing/cql/CQLTermNode.java @@ -23,9 +23,9 @@ public class CQLTermNode extends CQLNode { * null, but the term may not. */ public CQLTermNode(String index, CQLRelation relation, String term) { - this.index = index; - this.relation = relation; - this.term = term; + this.index = index; + this.relation = relation; + this.term = term; } public String getIndex() { return index; } @@ -33,12 +33,12 @@ public CQLTermNode(String index, CQLRelation relation, String term) { public String getTerm() { return term; } private static boolean isResultSetIndex(String qual) { - return (qual.equals("srw.resultSet") || - qual.equals("srw.resultSetId") || - qual.equals("srw.resultSetName") || - qual.equals("cql.resultSet") || - qual.equals("cql.resultSetId") || - qual.equals("cql.resultSetName")); + return (qual.equals("srw.resultSet") || + qual.equals("srw.resultSetId") || + qual.equals("srw.resultSetName") || + qual.equals("cql.resultSet") || + qual.equals("cql.resultSetId") || + qual.equals("cql.resultSetName")); } @Override @@ -47,18 +47,18 @@ public void traverse(CQLNodeVisitor visitor) { relation.traverse(visitor); visitor.onTermNode(this); } - + @Override public String getResultSetName() { - if (isResultSetIndex(index)) - return term; - else - return null; + if (isResultSetIndex(index)) + return term; + else + return null; } @Override void toXCQLInternal(XCQLBuilder b, int level, List prefixes, - List sortkeys) { + List sortkeys) { b.indent(level).append("\n"); renderPrefixes(b, level + 1, prefixes); b.indent(level + 1).append("").xq(index).append("\n"); @@ -70,247 +70,247 @@ void toXCQLInternal(XCQLBuilder b, int level, List prefixes, @Override public String toCQL() { - String quotedIndex = maybeQuote(index); - String quotedTerm = maybeQuote(term); - String res = quotedTerm; - - if (index != null && - !index.equalsIgnoreCase("srw.serverChoice") && - !index.equalsIgnoreCase("cql.serverChoice")) { - // ### We don't always need spaces around `relation'. - res = quotedIndex + " " + relation.toCQL() + " " + quotedTerm; - } - - return res; + String quotedIndex = maybeQuote(index); + String quotedTerm = maybeQuote(term); + String res = quotedTerm; + + if (index != null && + !index.equalsIgnoreCase("srw.serverChoice") && + !index.equalsIgnoreCase("cql.serverChoice")) { + // ### We don't always need spaces around `relation'. + res = quotedIndex + " " + relation.toCQL() + " " + quotedTerm; + } + + return res; } // ### Interaction between this and its callers is not good as // regards truncation of the term and generation of truncation // attributes. Change the interface to fix this. private List getAttrs(Properties config) throws PQFTranslationException { - List attrs = new ArrayList(); - - // Do this first so that if any other truncation or - // completeness attributes are generated, they "overwrite" - // those specified here. - // - // ### This approach relies on an unpleasant detail of Index - // Data's (admittedly definitive) implementation of PQF, - // and should not relied upon. - // - String attr = config.getProperty("always"); - if (attr != null) - attrs.add(attr); - - attr = config.getProperty("index." + index); - if (attr == null) - attr = config.getProperty("qualifier." + index); - if (attr == null) - throw new UnknownIndexException(index); - attrs.add(attr); - - String rel = relation.getBase(); - if (rel.equals("=")) { - rel = "eq"; - } else if (rel.equals("==")) { - rel = "exact"; - } else if (rel.equals("<=")) { - rel = "le"; - } else if (rel.equals(">=")) { - rel = "ge"; - } - // ### Handling "any" and "all" properly would involve breaking - // the string down into a bunch of individual words and ORring - // or ANDing them together. Another day. - attr = config.getProperty("relation." + rel); - if (attr == null) - throw new UnknownRelationException(rel); - attrs.add(attr); - - List mods = relation.getModifiers(); - for (int i = 0; i < mods.size(); i++) { - String type = mods.get(i).type; - attr = config.getProperty("relationModifier." + type); - if (attr == null) - throw new UnknownRelationModifierException(type); - attrs.add(attr); - } - - String pos = "any"; - String truncation = "none"; - String text = term; - if (text.length() > 0 && text.substring(0, 1).equals("^")) { - text = text.substring(1); // ### change not seen by caller - pos = "first"; - } - if (text.startsWith("*") && text.endsWith("*")) { - truncation = "both"; - } else if (text.startsWith("*")) { - truncation = "left"; - } else if (text.endsWith("*")) { - truncation = "right"; - } - int len = text.length(); - if (len > 0 && text.substring(len-1, len).equals("^")) { - text = text.substring(0, len-1); // ### change not seen by caller - pos = pos.equals("first") ? "firstAndLast" : "last"; - // ### in the firstAndLast case, the standard - // pqf.properties file specifies that we generate a - // completeness=whole-field attributem, which means that - // we don't generate a position attribute at all. Do we - // care? Does it matter? - } - - attr = config.getProperty("position." + pos); - if (attr == null) - throw new UnknownPositionException(pos); - attrs.add(attr); - - attr = config.getProperty("truncation." + truncation); - if (attr == null) - throw new UnknownTruncationException(truncation); - attrs.add(attr); - - attr = config.getProperty("structure." + rel); - if (attr == null) - attr = config.getProperty("structure.*"); - attrs.add(attr); - - return attrs; + List attrs = new ArrayList(); + + // Do this first so that if any other truncation or + // completeness attributes are generated, they "overwrite" + // those specified here. + // + // ### This approach relies on an unpleasant detail of Index + // Data's (admittedly definitive) implementation of PQF, + // and should not relied upon. + // + String attr = config.getProperty("always"); + if (attr != null) + attrs.add(attr); + + attr = config.getProperty("index." + index); + if (attr == null) + attr = config.getProperty("qualifier." + index); + if (attr == null) + throw new UnknownIndexException(index); + attrs.add(attr); + + String rel = relation.getBase(); + if (rel.equals("=")) { + rel = "eq"; + } else if (rel.equals("==")) { + rel = "exact"; + } else if (rel.equals("<=")) { + rel = "le"; + } else if (rel.equals(">=")) { + rel = "ge"; + } + // ### Handling "any" and "all" properly would involve breaking + // the string down into a bunch of individual words and ORring + // or ANDing them together. Another day. + attr = config.getProperty("relation." + rel); + if (attr == null) + throw new UnknownRelationException(rel); + attrs.add(attr); + + List mods = relation.getModifiers(); + for (int i = 0; i < mods.size(); i++) { + String type = mods.get(i).type; + attr = config.getProperty("relationModifier." + type); + if (attr == null) + throw new UnknownRelationModifierException(type); + attrs.add(attr); + } + + String pos = "any"; + String truncation = "none"; + String text = term; + if (text.length() > 0 && text.substring(0, 1).equals("^")) { + text = text.substring(1); // ### change not seen by caller + pos = "first"; + } + if (text.startsWith("*") && text.endsWith("*")) { + truncation = "both"; + } else if (text.startsWith("*")) { + truncation = "left"; + } else if (text.endsWith("*")) { + truncation = "right"; + } + int len = text.length(); + if (len > 0 && text.substring(len-1, len).equals("^")) { + text = text.substring(0, len-1); // ### change not seen by caller + pos = pos.equals("first") ? "firstAndLast" : "last"; + // ### in the firstAndLast case, the standard + // pqf.properties file specifies that we generate a + // completeness=whole-field attributem, which means that + // we don't generate a position attribute at all. Do we + // care? Does it matter? + } + + attr = config.getProperty("position." + pos); + if (attr == null) + throw new UnknownPositionException(pos); + attrs.add(attr); + + attr = config.getProperty("truncation." + truncation); + if (attr == null) + throw new UnknownTruncationException(truncation); + attrs.add(attr); + + attr = config.getProperty("structure." + rel); + if (attr == null) + attr = config.getProperty("structure.*"); + attrs.add(attr); + + return attrs; } @Override public String toPQF(Properties config) throws PQFTranslationException { - if (isResultSetIndex(index)) { - // Special case: ignore relation, modifiers, wildcards, etc. - // There's parallel code in toType1BER() - return "@set " + maybeQuote(term); - } - - List attrs = getAttrs(config); - - String attr, s = ""; - for (int i = 0; i < attrs.size(); i++) { - attr = (String) attrs.get(i); - s += "@attr " + attr.replace(" ", " @attr ") + " "; - } - - String text = term; - if (text.length() > 0 && text.substring(0, 1).equals("^")) - text = text.substring(1); - int len = text.length(); - if (len > 0 && text.substring(len-1, len).equals("^")) - text = text.substring(0, len-1); - - len = text.length(); - if (text.startsWith("*") && text.endsWith("*")) { - text = text.substring(1, len-1); - } else if (text.startsWith("*")) { - text = text.substring(1); - } else if (text.endsWith("*")) { - text = text.substring(0, len-1); - } - - return s + maybeQuote(text); + if (isResultSetIndex(index)) { + // Special case: ignore relation, modifiers, wildcards, etc. + // There's parallel code in toType1BER() + return "@set " + maybeQuote(term); + } + + List attrs = getAttrs(config); + + String attr, s = ""; + for (int i = 0; i < attrs.size(); i++) { + attr = (String) attrs.get(i); + s += "@attr " + attr.replace(" ", " @attr ") + " "; + } + + String text = term; + if (text.length() > 0 && text.substring(0, 1).equals("^")) + text = text.substring(1); + int len = text.length(); + if (len > 0 && text.substring(len-1, len).equals("^")) + text = text.substring(0, len-1); + + len = text.length(); + if (text.startsWith("*") && text.endsWith("*")) { + text = text.substring(1, len-1); + } else if (text.startsWith("*")) { + text = text.substring(1); + } else if (text.endsWith("*")) { + text = text.substring(0, len-1); + } + + return s + maybeQuote(text); } static String maybeQuote(String str) { if (str == null) return null; - // There _must_ be a better way to make this test ... - if (str.length() == 0 || - str.indexOf('"') != -1 || - str.indexOf(' ') != -1 || - str.indexOf('\t') != -1 || - str.indexOf('=') != -1 || - str.indexOf('<') != -1 || - str.indexOf('>') != -1 || - str.indexOf('/') != -1 || - str.indexOf('(') != -1 || - str.indexOf(')') != -1) { - str = '"' + str.replace("\"", "\\\"") + '"'; - } - - return str; + // There _must_ be a better way to make this test ... + if (str.length() == 0 || + str.indexOf('"') != -1 || + str.indexOf(' ') != -1 || + str.indexOf('\t') != -1 || + str.indexOf('=') != -1 || + str.indexOf('<') != -1 || + str.indexOf('>') != -1 || + str.indexOf('/') != -1 || + str.indexOf('(') != -1 || + str.indexOf(')') != -1) { + str = '"' + str.replace("\"", "\\\"") + '"'; + } + + return str; } @Override public byte[] toType1BER(Properties config) throws PQFTranslationException { - if (isResultSetIndex(index)) { - // Special case: ignore relation, modifiers, wildcards, etc. - // There's parallel code in toPQF() - byte[] operand = new byte[term.length()+100]; - int offset; - offset = putTag(CONTEXT, 0, CONSTRUCTED, operand, 0); // op - operand[offset++] = (byte)(0x80&0xff); // indefinite length - offset = putTag(CONTEXT, 31, PRIMITIVE, operand, offset); // ResultSetId - byte[] t = term.getBytes(); - offset = putLen(t.length, operand, offset); - System.arraycopy(t, 0, operand, offset, t.length); - offset += t.length; - operand[offset++] = 0x00; // end of Operand - operand[offset++] = 0x00; - byte[] o = new byte[offset]; - System.arraycopy(operand, 0, o, 0, offset); - return o; - } - - String text = term; - if (text.length() > 0 && text.substring(0, 1).equals("^")) - text = text.substring(1); - int len = text.length(); - if (len > 0 && text.substring(len-1, len).equals("^")) - text = text.substring(0, len-1); - - String attr, attrList; - byte[] operand = new byte[text.length()+100]; - int i, j, offset, type, value; - offset = putTag(CONTEXT, 0, CONSTRUCTED, operand, 0); // op - operand[offset++]=(byte)(0x80&0xff); // indefinite length - offset = putTag(CONTEXT, 102, CONSTRUCTED, operand, offset); // AttributesPlusTerm - operand[offset++] = (byte)(0x80&0xff); // indefinite length - offset = putTag(CONTEXT, 44, CONSTRUCTED, operand, offset); // AttributeList - operand[offset++] = (byte)(0x80&0xff); // indefinite length - - List attrs = getAttrs(config); - for(i = 0; i < attrs.size(); i++) { - attrList = (String) attrs.get(i); - java.util.StringTokenizer st = - new java.util.StringTokenizer(attrList); - while (st.hasMoreTokens()) { - attr = st.nextToken(); - j = attr.indexOf('='); - offset = putTag(UNIVERSAL, SEQUENCE, CONSTRUCTED, operand, offset); - operand[offset++] = (byte)(0x80&0xff); - offset = putTag(CONTEXT, 120, PRIMITIVE, operand, offset); - type = Integer.parseInt(attr.substring(0, j)); - offset = putLen(numLen(type), operand, offset); - offset = putNum(type, operand, offset); - - offset = putTag(CONTEXT, 121, PRIMITIVE, operand, offset); - value = Integer.parseInt(attr.substring(j+1)); - offset = putLen(numLen(value), operand, offset); - offset = putNum(value, operand, offset); - operand[offset++] = 0x00; // end of SEQUENCE - operand[offset++] = 0x00; - } - } - operand[offset++] = 0x00; // end of AttributeList - operand[offset++] = 0x00; - - offset = putTag(CONTEXT, 45, PRIMITIVE, operand, offset); // general Term - byte[] t = text.getBytes(); - offset = putLen(t.length, operand, offset); - System.arraycopy(t, 0, operand, offset, t.length); - offset += t.length; - - operand[offset++] = 0x00; // end of AttributesPlusTerm - operand[offset++] = 0x00; - operand[offset++] = 0x00; // end of Operand - operand[offset++] = 0x00; - byte[] o = new byte[offset]; - System.arraycopy(operand, 0, o, 0, offset); - return o; + if (isResultSetIndex(index)) { + // Special case: ignore relation, modifiers, wildcards, etc. + // There's parallel code in toPQF() + byte[] operand = new byte[term.length()+100]; + int offset; + offset = putTag(CONTEXT, 0, CONSTRUCTED, operand, 0); // op + operand[offset++] = (byte)(0x80&0xff); // indefinite length + offset = putTag(CONTEXT, 31, PRIMITIVE, operand, offset); // ResultSetId + byte[] t = term.getBytes(); + offset = putLen(t.length, operand, offset); + System.arraycopy(t, 0, operand, offset, t.length); + offset += t.length; + operand[offset++] = 0x00; // end of Operand + operand[offset++] = 0x00; + byte[] o = new byte[offset]; + System.arraycopy(operand, 0, o, 0, offset); + return o; + } + + String text = term; + if (text.length() > 0 && text.substring(0, 1).equals("^")) + text = text.substring(1); + int len = text.length(); + if (len > 0 && text.substring(len-1, len).equals("^")) + text = text.substring(0, len-1); + + String attr, attrList; + byte[] operand = new byte[text.length()+100]; + int i, j, offset, type, value; + offset = putTag(CONTEXT, 0, CONSTRUCTED, operand, 0); // op + operand[offset++]=(byte)(0x80&0xff); // indefinite length + offset = putTag(CONTEXT, 102, CONSTRUCTED, operand, offset); // AttributesPlusTerm + operand[offset++] = (byte)(0x80&0xff); // indefinite length + offset = putTag(CONTEXT, 44, CONSTRUCTED, operand, offset); // AttributeList + operand[offset++] = (byte)(0x80&0xff); // indefinite length + + List attrs = getAttrs(config); + for(i = 0; i < attrs.size(); i++) { + attrList = (String) attrs.get(i); + java.util.StringTokenizer st = + new java.util.StringTokenizer(attrList); + while (st.hasMoreTokens()) { + attr = st.nextToken(); + j = attr.indexOf('='); + offset = putTag(UNIVERSAL, SEQUENCE, CONSTRUCTED, operand, offset); + operand[offset++] = (byte)(0x80&0xff); + offset = putTag(CONTEXT, 120, PRIMITIVE, operand, offset); + type = Integer.parseInt(attr.substring(0, j)); + offset = putLen(numLen(type), operand, offset); + offset = putNum(type, operand, offset); + + offset = putTag(CONTEXT, 121, PRIMITIVE, operand, offset); + value = Integer.parseInt(attr.substring(j+1)); + offset = putLen(numLen(value), operand, offset); + offset = putNum(value, operand, offset); + operand[offset++] = 0x00; // end of SEQUENCE + operand[offset++] = 0x00; + } + } + operand[offset++] = 0x00; // end of AttributeList + operand[offset++] = 0x00; + + offset = putTag(CONTEXT, 45, PRIMITIVE, operand, offset); // general Term + byte[] t = text.getBytes(); + offset = putLen(t.length, operand, offset); + System.arraycopy(t, 0, operand, offset, t.length); + offset += t.length; + + operand[offset++] = 0x00; // end of AttributesPlusTerm + operand[offset++] = 0x00; + operand[offset++] = 0x00; // end of Operand + operand[offset++] = 0x00; + byte[] o = new byte[offset]; + System.arraycopy(operand, 0, o, 0, offset); + return o; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLTokenizer.java b/src/main/java/org/z3950/zing/cql/CQLTokenizer.java index 8542dd9..a73d264 100644 --- a/src/main/java/org/z3950/zing/cql/CQLTokenizer.java +++ b/src/main/java/org/z3950/zing/cql/CQLTokenizer.java @@ -5,53 +5,53 @@ * @author jakub */ public interface CQLTokenizer { - - public static final int TT_EOF = -1; - public static final int TT_WORD = -3; - public static final int TT_NOTHING = -4; - - public final static int TT_STRING = 999; // quoted string - public final static int TT_LE = 1000; // The "<=" relation - public final static int TT_GE = 1001; // The ">=" relation - public final static int TT_NE = 1002; // The "<>" relation - public final static int TT_EQEQ = 1003; // The "==" relation - public final static int TT_AND = 1004; // The "and" boolean - public final static int TT_OR = 1005; // The "or" boolean - public final static int TT_NOT = 1006; // The "not" boolean - public final static int TT_PROX = 1007; // The "prox" boolean - public final static int TT_SORTBY = 1008; // The "sortby" operator - - /** - * Consume next input token - */ - public void move(); - - /** - * Return the value of the last consumed token - * @return value of the token - */ - public String value(); - - /** - * Return the type of the last consumed token - * @return last consumed token - */ - public int what(); - - /** - * Render the type and value of the last consumed token - * @return human-readable string - */ - public String render(); - - /** - * Render specified token type - * @param what token type - * @param quote true, if single characters should be quoted for readability - * @return human-readable string - */ - public String render(int what, boolean quote); - - public int pos(); - + + public static final int TT_EOF = -1; + public static final int TT_WORD = -3; + public static final int TT_NOTHING = -4; + + public final static int TT_STRING = 999; // quoted string + public final static int TT_LE = 1000; // The "<=" relation + public final static int TT_GE = 1001; // The ">=" relation + public final static int TT_NE = 1002; // The "<>" relation + public final static int TT_EQEQ = 1003; // The "==" relation + public final static int TT_AND = 1004; // The "and" boolean + public final static int TT_OR = 1005; // The "or" boolean + public final static int TT_NOT = 1006; // The "not" boolean + public final static int TT_PROX = 1007; // The "prox" boolean + public final static int TT_SORTBY = 1008; // The "sortby" operator + + /** + * Consume next input token + */ + public void move(); + + /** + * Return the value of the last consumed token + * @return value of the token + */ + public String value(); + + /** + * Return the type of the last consumed token + * @return last consumed token + */ + public int what(); + + /** + * Render the type and value of the last consumed token + * @return human-readable string + */ + public String render(); + + /** + * Render specified token type + * @param what token type + * @param quote true, if single characters should be quoted for readability + * @return human-readable string + */ + public String render(int what, boolean quote); + + public int pos(); + } diff --git a/src/main/java/org/z3950/zing/cql/MissingParameterException.java b/src/main/java/org/z3950/zing/cql/MissingParameterException.java index b52b2cb..2ae831e 100644 --- a/src/main/java/org/z3950/zing/cql/MissingParameterException.java +++ b/src/main/java/org/z3950/zing/cql/MissingParameterException.java @@ -11,6 +11,6 @@ public class MissingParameterException extends Exception { * The name of the property whose value was required but not supplied. */ public MissingParameterException(String s) { - super(s); + super(s); } } diff --git a/src/main/java/org/z3950/zing/cql/Modifier.java b/src/main/java/org/z3950/zing/cql/Modifier.java index af68453..8a97dee 100644 --- a/src/main/java/org/z3950/zing/cql/Modifier.java +++ b/src/main/java/org/z3950/zing/cql/Modifier.java @@ -19,10 +19,10 @@ public class Modifier { * and value. */ public Modifier(String type, String comparison, String value) { - this.type = type; - this.comparison = comparison; - this.value = value; - //System.err.println("Made new modifier with " + "type='" + type + "', " + "comparison='" + comparison + "', " + "value='" + value + "',\n"); + this.type = type; + this.comparison = comparison; + this.value = value; + //System.err.println("Made new modifier with " + "type='" + type + "', " + "comparison='" + comparison + "', " + "value='" + value + "',\n"); } /** @@ -30,48 +30,48 @@ public Modifier(String type, String comparison, String value) { * comparison or value. */ public Modifier(String type) { - this.type = type; - //System.err.println("Made new modifier of type '" + type + "'\n"); + this.type = type; + //System.err.println("Made new modifier of type '" + type + "'\n"); } /** * Returns the type with which the Modifier was created. */ public String getType() { - return type; + return type; } /** * Returns the comparison with which the Modifier was created. */ public String getComparison() { - return comparison; + return comparison; } /** * Returns the value with which the Modifier was created. */ public String getValue() { - return value; + return value; } void toXCQLInternal(XCQLBuilder b, int level, String relationElement) { - b.indent(level).append("\n"); + b.indent(level).append("\n"); b.indent(level + 1).append(""); b.xq(type).append("\n"); - if (value != null) { + if (value != null) { b.indent(level + 1).append("<").append(relationElement).append(">"); b.xq(comparison).append("\n"); b.indent(level + 1).append(""); b.xq(value).append("\n"); - } - b.indent(level).append("\n"); + } + b.indent(level).append("\n"); } public String toCQL() { - StringBuilder buf = new StringBuilder(type); - if (value != null) - buf.append(" ").append(comparison).append(" ").append(value); - return buf.toString(); + StringBuilder buf = new StringBuilder(type); + if (value != null) + buf.append(" ").append(comparison).append(" ").append(value); + return buf.toString(); } } diff --git a/src/main/java/org/z3950/zing/cql/ModifierSet.java b/src/main/java/org/z3950/zing/cql/ModifierSet.java index 754af1e..f2989d4 100644 --- a/src/main/java/org/z3950/zing/cql/ModifierSet.java +++ b/src/main/java/org/z3950/zing/cql/ModifierSet.java @@ -25,15 +25,15 @@ public class ModifierSet { * Creates a new ModifierSet with the specified base. */ public ModifierSet(String base) { - this.base = base; - modifiers = new ArrayList(); + this.base = base; + modifiers = new ArrayList(); } /** * Returns the base string with which the ModifierSet was created. */ public String getBase() { - return base; + return base; } /** @@ -41,8 +41,8 @@ public String getBase() { * comparison and value to a ModifierSet. */ public void addModifier(String type, String comparison, String value) { - Modifier modifier = new Modifier(type, comparison, value); - modifiers.add(modifier); + Modifier modifier = new Modifier(type, comparison, value); + modifiers.add(modifier); } /** @@ -50,8 +50,8 @@ public void addModifier(String type, String comparison, String value) { * comparison and value, to a ModifierSet. */ public void addModifier(String type) { - Modifier modifier = new Modifier(type); - modifiers.add(modifier); + Modifier modifier = new Modifier(type); + modifiers.add(modifier); } /** @@ -59,13 +59,13 @@ public void addModifier(String type) { * that corresponds to the specified type. */ public String modifier(String type) { - int n = modifiers.size(); - for (int i = 0; i < n; i++) { - Modifier mod = modifiers.get(i); - if (mod.type.equals(type)) - return mod.value; - } - return null; + int n = modifiers.size(); + for (int i = 0; i < n; i++) { + Modifier mod = modifiers.get(i); + if (mod.type.equals(type)) + return mod.value; + } + return null; } /** @@ -74,45 +74,45 @@ public String modifier(String type) { * An array of Modifiers. */ public List getModifiers() { - return modifiers; + return modifiers; } void toXCQLInternal(XCQLBuilder b, int level, - String topLevelElement, String valueElement) { - b.indent(level).append("<").append(topLevelElement). + String topLevelElement, String valueElement) { + b.indent(level).append("<").append(topLevelElement). append(">\n").indent(level + 1).append("<"). append(valueElement).append(">").xq(base).append("\n"); - if (modifiers.size() > 0) { - b.indent(level + 1).append("\n"); - for (int i = 0; i < modifiers.size(); i++) { + if (modifiers.size() > 0) { + b.indent(level + 1).append("\n"); + for (int i = 0; i < modifiers.size(); i++) { modifiers.get(i).toXCQLInternal(b, level+2, "comparison"); - } - b.indent(level + 1).append("\n"); - } - b.indent(level).append("\n"); + } + b.indent(level + 1).append("\n"); + } + b.indent(level).append("\n"); } public String toCQL() { - StringBuilder buf = new StringBuilder(base); - for (int i = 0; i < modifiers.size(); i++) { - buf.append("/").append(modifiers.get(i).toCQL()); - } + StringBuilder buf = new StringBuilder(base); + for (int i = 0; i < modifiers.size(); i++) { + buf.append("/").append(modifiers.get(i).toCQL()); + } - return buf.toString(); + return buf.toString(); } public static void main(String[] args) { - if (args.length < 1) { - System.err.println("Usage: ModifierSet [ ]..."); - System.exit(1); - } + if (args.length < 1) { + System.err.println("Usage: ModifierSet [ ]..."); + System.exit(1); + } - ModifierSet res = new ModifierSet(args[0]); - for (int i = 1; i < args.length; i += 3) { - res.addModifier(args[i], args[i+1], args[i+2]); - } + ModifierSet res = new ModifierSet(args[0]); + for (int i = 1; i < args.length; i += 3) { + res.addModifier(args[i], args[i+1], args[i+2]); + } - System.out.println(res.toCQL()); + System.out.println(res.toCQL()); } } diff --git a/src/main/java/org/z3950/zing/cql/PQFTranslationException.java b/src/main/java/org/z3950/zing/cql/PQFTranslationException.java index a095776..b214b42 100644 --- a/src/main/java/org/z3950/zing/cql/PQFTranslationException.java +++ b/src/main/java/org/z3950/zing/cql/PQFTranslationException.java @@ -6,6 +6,6 @@ */ public class PQFTranslationException extends Exception { PQFTranslationException(String s) { - super(s); + super(s); } } diff --git a/src/main/java/org/z3950/zing/cql/UnknownPositionException.java b/src/main/java/org/z3950/zing/cql/UnknownPositionException.java index c7d9c12..4bd1218 100644 --- a/src/main/java/org/z3950/zing/cql/UnknownPositionException.java +++ b/src/main/java/org/z3950/zing/cql/UnknownPositionException.java @@ -18,6 +18,6 @@ public class UnknownPositionException extends PQFTranslationException { * The position for which there was no PQF configuration. */ public UnknownPositionException(String s) { - super(s); + super(s); } } diff --git a/src/main/java/org/z3950/zing/cql/UnknownRelationException.java b/src/main/java/org/z3950/zing/cql/UnknownRelationException.java index d4998b0..e646453 100644 --- a/src/main/java/org/z3950/zing/cql/UnknownRelationException.java +++ b/src/main/java/org/z3950/zing/cql/UnknownRelationException.java @@ -16,6 +16,6 @@ public class UnknownRelationException extends PQFTranslationException { * The relation for which there was no PQF configuration. */ public UnknownRelationException(String s) { - super(s); + super(s); } } diff --git a/src/main/java/org/z3950/zing/cql/UnknownRelationModifierException.java b/src/main/java/org/z3950/zing/cql/UnknownRelationModifierException.java index b27d952..4d5cc2a 100644 --- a/src/main/java/org/z3950/zing/cql/UnknownRelationModifierException.java +++ b/src/main/java/org/z3950/zing/cql/UnknownRelationModifierException.java @@ -16,6 +16,6 @@ public class UnknownRelationModifierException extends PQFTranslationException { * The relation modifier for which there was no PQF configuration. */ public UnknownRelationModifierException(String s) { - super(s); + super(s); } } diff --git a/src/main/java/org/z3950/zing/cql/UnknownTruncationException.java b/src/main/java/org/z3950/zing/cql/UnknownTruncationException.java index 024fd2e..5d1099b 100644 --- a/src/main/java/org/z3950/zing/cql/UnknownTruncationException.java +++ b/src/main/java/org/z3950/zing/cql/UnknownTruncationException.java @@ -11,15 +11,15 @@ * */ public class UnknownTruncationException extends PQFTranslationException { - private static final long serialVersionUID = 6971993723734811253L; + private static final long serialVersionUID = 6971993723734811253L; - /** - * Creates a new UnknownTruncationException. - * - * @param s - * The truncation for which there was no PQF configuration. - */ - public UnknownTruncationException(String s) { - super(s); - } + /** + * Creates a new UnknownTruncationException. + * + * @param s + * The truncation for which there was no PQF configuration. + */ + public UnknownTruncationException(String s) { + super(s); + } } diff --git a/src/main/java/org/z3950/zing/cql/XCQLBuilder.java b/src/main/java/org/z3950/zing/cql/XCQLBuilder.java index 9b3d8fd..0e7cb27 100644 --- a/src/main/java/org/z3950/zing/cql/XCQLBuilder.java +++ b/src/main/java/org/z3950/zing/cql/XCQLBuilder.java @@ -5,45 +5,45 @@ * @author jakub */ class XCQLBuilder { - private StringBuilder sb; + private StringBuilder sb; - XCQLBuilder(StringBuilder sb) { - this.sb = sb; - } + XCQLBuilder(StringBuilder sb) { + this.sb = sb; + } + + XCQLBuilder indent(int level) { + while (level-- > 0) { + sb.append(" "); + } + return this; + } - XCQLBuilder indent(int level) { - while (level-- > 0) { - sb.append(" "); + XCQLBuilder xq(String str) { + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + switch (c) { + case '<': + sb.append("<"); + break; + case '>': + sb.append(">"); + break; + case '&': + sb.append("&"); + break; + default: + sb.append(c); + } + } + return this; } - return this; - } - XCQLBuilder xq(String str) { - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - switch (c) { - case '<': - sb.append("<"); - break; - case '>': - sb.append(">"); - break; - case '&': - sb.append("&"); - break; - default: - sb.append(c); - } + XCQLBuilder append(String str) { + sb.append(str); + return this; } - return this; - } - - XCQLBuilder append(String str) { - sb.append(str); - return this; - } - public String toString() { - return sb.toString(); - } + public String toString() { + return sb.toString(); + } } \ No newline at end of file diff --git a/src/test/java/org/z3950/zing/cql/CQLNodeVisitorTest.java b/src/test/java/org/z3950/zing/cql/CQLNodeVisitorTest.java index 8324098..2cd7cdc 100644 --- a/src/test/java/org/z3950/zing/cql/CQLNodeVisitorTest.java +++ b/src/test/java/org/z3950/zing/cql/CQLNodeVisitorTest.java @@ -15,117 +15,117 @@ * @author jakub */ public class CQLNodeVisitorTest { - - public CQLNodeVisitorTest() { - } - - @BeforeClass - public static void setUpClass() { - } - - @AfterClass - public static void tearDownClass() { - } - - @Before - public void setUp() { - } - - @After - public void tearDown() { - } - - @Test - public void testPrefixVisitor() { - String cql = "((x=a and y=b) or z=c)"; - String epxected = "@or @and @attr 1=x a @attr 1=y b @attr 1=z c"; - CQLParser p = new CQLParser(CQLParser.V1POINT2); - out.println("Parsing "+cql); - try { - CQLNode n = p.parse(cql); - CQLNodeVisitor v = new CQLDefaultNodeVisitor() { - String actual = ""; - String termSep = ""; - @Override - public void onBooleanNodeStart(CQLBooleanNode node) { - String op = ""; - switch (node.getOperator()) { - case AND: op = "@and"; break; - case OR: op = "@or"; break; - } - actual += op + " "; - } - - @Override - public void onTermNode(CQLTermNode node) { - actual += termSep + "@attr 1="+node.getIndex() + " " + node.getTerm(); - termSep = " "; - } - - @Override - public String toString() { - return actual; - } - }; - n.traverse(v); - out.println(v); - assertEquals(epxected, v.toString()); - } catch (CQLParseException ex) { - fail(ex.getMessage()); - } catch (IOException ex) { - fail(ex.getMessage()); + + public CQLNodeVisitorTest() { } - } - - @Test - public void testInfixVisitor() { - String cql = "((x=a and y=b) or z=c)"; - String epxected = "((x:a OG y:b) ELLER z:c)"; - CQLParser p = new CQLParser(CQLParser.V1POINT2); - out.println("Parsing "+cql); - try { - CQLNode n = p.parse(cql); - CQLNodeVisitor v = new CQLDefaultNodeVisitor() { - String actual = ""; - - @Override - public void onBooleanNodeStart(CQLBooleanNode node) { - actual += "("; - } - - @Override - public void onBooleanNodeOp(CQLBooleanNode node) { - String op = ""; - switch (node.getOperator()) { - case AND: op = "OG"; break; - case OR: op = "ELLER"; break; - } - actual += " " + op + " "; - } - @Override - public void onBooleanNodeEnd(CQLBooleanNode node) { - actual += ")"; - } - - @Override - public void onTermNode(CQLTermNode node) { - actual += node.getIndex() + ":" + node.getTerm(); + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void testPrefixVisitor() { + String cql = "((x=a and y=b) or z=c)"; + String epxected = "@or @and @attr 1=x a @attr 1=y b @attr 1=z c"; + CQLParser p = new CQLParser(CQLParser.V1POINT2); + out.println("Parsing "+cql); + try { + CQLNode n = p.parse(cql); + CQLNodeVisitor v = new CQLDefaultNodeVisitor() { + String actual = ""; + String termSep = ""; + @Override + public void onBooleanNodeStart(CQLBooleanNode node) { + String op = ""; + switch (node.getOperator()) { + case AND: op = "@and"; break; + case OR: op = "@or"; break; + } + actual += op + " "; + } + + @Override + public void onTermNode(CQLTermNode node) { + actual += termSep + "@attr 1="+node.getIndex() + " " + node.getTerm(); + termSep = " "; + } + + @Override + public String toString() { + return actual; + } + }; + n.traverse(v); + out.println(v); + assertEquals(epxected, v.toString()); + } catch (CQLParseException ex) { + fail(ex.getMessage()); + } catch (IOException ex) { + fail(ex.getMessage()); } - - @Override - public String toString() { - return actual; + } + + @Test + public void testInfixVisitor() { + String cql = "((x=a and y=b) or z=c)"; + String epxected = "((x:a OG y:b) ELLER z:c)"; + CQLParser p = new CQLParser(CQLParser.V1POINT2); + out.println("Parsing "+cql); + try { + CQLNode n = p.parse(cql); + CQLNodeVisitor v = new CQLDefaultNodeVisitor() { + String actual = ""; + + @Override + public void onBooleanNodeStart(CQLBooleanNode node) { + actual += "("; + } + + @Override + public void onBooleanNodeOp(CQLBooleanNode node) { + String op = ""; + switch (node.getOperator()) { + case AND: op = "OG"; break; + case OR: op = "ELLER"; break; + } + actual += " " + op + " "; + } + + @Override + public void onBooleanNodeEnd(CQLBooleanNode node) { + actual += ")"; + } + + @Override + public void onTermNode(CQLTermNode node) { + actual += node.getIndex() + ":" + node.getTerm(); + } + + @Override + public String toString() { + return actual; + } + }; + n.traverse(v); + out.println(v); + assertEquals(epxected, v.toString()); + } catch (CQLParseException ex) { + fail(ex.getMessage()); + } catch (IOException ex) { + fail(ex.getMessage()); } - }; - n.traverse(v); - out.println(v); - assertEquals(epxected, v.toString()); - } catch (CQLParseException ex) { - fail(ex.getMessage()); - } catch (IOException ex) { - fail(ex.getMessage()); } - } - + } diff --git a/src/test/java/org/z3950/zing/cql/CQLParserTest.java b/src/test/java/org/z3950/zing/cql/CQLParserTest.java index ed0c1ab..852243e 100644 --- a/src/test/java/org/z3950/zing/cql/CQLParserTest.java +++ b/src/test/java/org/z3950/zing/cql/CQLParserTest.java @@ -28,166 +28,166 @@ * @author jakub */ public class CQLParserTest { - public CQLParserTest() { - } - - @BeforeClass - public static void setUpClass() { - } - - @AfterClass - public static void tearDownClass() { - } - - @Before - public void setUp() { - } - - @After - public void tearDown() { - } + public CQLParserTest() { + } - /** - * Test of main method, of class CQLParser. - */ - @Test - public void testRegressionQueries() throws IOException { - System.out.println("Testing the parser using pre-canned regression queries..."); - //we might be running the test from within the jar - //list all resource dirs, then traverse them - String[] dirs = getResourceListing(this.getClass(), "regression"); - for (String dir : dirs) { - String files[] = getResourceListing(this.getClass(), "regression/" + dir); - for (String file : files) { - if (!file.endsWith(".cql")) continue; - out.println("Parsing "+dir+"/"+file); - InputStream is = this.getClass().getResourceAsStream("/regression/"+dir+"/"+file); - BufferedReader reader = null, reader2 = null; - try { - reader = new BufferedReader(new InputStreamReader(is)); - String input = reader.readLine(); - out.println("Query: "+input); - String result; - try { - CQLParser parser = new CQLParser(); - CQLNode parsed = parser.parse(input); - result = parsed.toXCQL(); - } catch (CQLParseException pe) { - result = pe.getMessage() + "\n"; - } - out.println("Parsed:"); - out.println(result); - //read the expected xcql output - String expected = ""; - String prefix = file.substring(0, file.length()-4); - InputStream is2 = this.getClass() - .getResourceAsStream("/regression/"+dir+"/"+prefix+".xcql"); - if (is2 != null) { - reader2 = new BufferedReader(new InputStreamReader(is2)); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader2.readLine()) != null) { - sb.append(line).append("\n"); - } - expected = sb.toString(); - } - out.println("Expected: "); - out.println(expected); - assertEquals("Assertion failure for "+dir+"/"+file, expected, result); - } finally { - if (reader != null) reader.close(); - if (reader2 != null) reader2.close(); - } - } + @BeforeClass + public static void setUpClass() { } - } - - /** - * Test the integrity of the parser as follows: - * - Generate a random tree with CQLGenerator - * - Serialize it - * - Canonicalise it by running through the parser - * - Compare the before-and-after versions. - * Since the CQLGenerator output is in canonical form anyway, the - * before-and-after versions should be identical. This process exercises - * the comprehensiveness and bullet-proofing of the parser, as well as - * the accuracy of the rendering. - * @throws IOException - * @throws MissingParameterException - */ - @Test - public void testRandomQueries() throws IOException, MissingParameterException { - out.println("Testing the parser using 100 randomly generated queries..."); - Properties params = new Properties(); - InputStream is = getClass().getResourceAsStream("/generate.properties"); - if (is == null) - fail("Cannot locate generate.properties"); - params.load(is); - is.close(); - CQLGenerator generator = new CQLGenerator(params); - for (int i=0; i<1000; i++) { - CQLNode random = generator.generate(); - String expected = random.toCQL(); - out.println("Generated query: "+expected); - CQLParser parser = new CQLParser(); - try { - CQLNode parsed = parser.parse(expected); - String result = parsed.toCQL(); - assertEquals(expected, result); - } catch (CQLParseException pe) { - fail("Generated query failed to parse: "+pe.getMessage()); - } + + @AfterClass + public static void tearDownClass() { } - } - - //helper methods follow - //TODO move to masterkey-common - - @SuppressWarnings("rawtypes") - public static String[] getResourceListing(Class clazz, String path) throws - IOException { - URL dirURL = clazz.getClassLoader().getResource(path); - if (dirURL != null && dirURL.getProtocol().equals("file")) { - /* A file path: easy enough */ - try { - return new File(dirURL.toURI()).list(); - } catch (URISyntaxException use) { - throw new UnsupportedOperationException(use); - } + + @Before + public void setUp() { } - if (dirURL == null) { - /* - * In case of a jar file, we can't actually find a directory. - * Have to assume the same jar as clazz. - */ - String me = clazz.getName().replace(".", "/") + ".class"; - dirURL = clazz.getClassLoader().getResource(me); + @After + public void tearDown() { } - if (dirURL.getProtocol().equals("jar")) { - /* A JAR path */ - String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf( - "!")); //strip out only the JAR file - JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8")); - Enumeration entries = jar.entries(); //gives ALL entries in jar - Set result = new HashSet(); //avoid duplicates in case it is a subdirectory - while (entries.hasMoreElements()) { - String name = entries.nextElement().getName(); - if (name.startsWith(path)) { //filter according to the path - String entry = name.substring(path.length()); - int checkSubdir = entry.indexOf("/"); - if (checkSubdir >= 0) { - // if it is a subdirectory, we just return the directory name - entry = entry.substring(0, checkSubdir); - } - result.add(entry); + /** + * Test of main method, of class CQLParser. + */ + @Test + public void testRegressionQueries() throws IOException { + System.out.println("Testing the parser using pre-canned regression queries..."); + //we might be running the test from within the jar + //list all resource dirs, then traverse them + String[] dirs = getResourceListing(this.getClass(), "regression"); + for (String dir : dirs) { + String files[] = getResourceListing(this.getClass(), "regression/" + dir); + for (String file : files) { + if (!file.endsWith(".cql")) continue; + out.println("Parsing "+dir+"/"+file); + InputStream is = this.getClass().getResourceAsStream("/regression/"+dir+"/"+file); + BufferedReader reader = null, reader2 = null; + try { + reader = new BufferedReader(new InputStreamReader(is)); + String input = reader.readLine(); + out.println("Query: "+input); + String result; + try { + CQLParser parser = new CQLParser(); + CQLNode parsed = parser.parse(input); + result = parsed.toXCQL(); + } catch (CQLParseException pe) { + result = pe.getMessage() + "\n"; + } + out.println("Parsed:"); + out.println(result); + //read the expected xcql output + String expected = ""; + String prefix = file.substring(0, file.length()-4); + InputStream is2 = this.getClass() + .getResourceAsStream("/regression/"+dir+"/"+prefix+".xcql"); + if (is2 != null) { + reader2 = new BufferedReader(new InputStreamReader(is2)); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader2.readLine()) != null) { + sb.append(line).append("\n"); + } + expected = sb.toString(); + } + out.println("Expected: "); + out.println(expected); + assertEquals("Assertion failure for "+dir+"/"+file, expected, result); + } finally { + if (reader != null) reader.close(); + if (reader2 != null) reader2.close(); + } + } + } + } + + /** + * Test the integrity of the parser as follows: + * - Generate a random tree with CQLGenerator + * - Serialize it + * - Canonicalise it by running through the parser + * - Compare the before-and-after versions. + * Since the CQLGenerator output is in canonical form anyway, the + * before-and-after versions should be identical. This process exercises + * the comprehensiveness and bullet-proofing of the parser, as well as + * the accuracy of the rendering. + * @throws IOException + * @throws MissingParameterException + */ + @Test + public void testRandomQueries() throws IOException, MissingParameterException { + out.println("Testing the parser using 100 randomly generated queries..."); + Properties params = new Properties(); + InputStream is = getClass().getResourceAsStream("/generate.properties"); + if (is == null) + fail("Cannot locate generate.properties"); + params.load(is); + is.close(); + CQLGenerator generator = new CQLGenerator(params); + for (int i=0; i<1000; i++) { + CQLNode random = generator.generate(); + String expected = random.toCQL(); + out.println("Generated query: "+expected); + CQLParser parser = new CQLParser(); + try { + CQLNode parsed = parser.parse(expected); + String result = parsed.toCQL(); + assertEquals(expected, result); + } catch (CQLParseException pe) { + fail("Generated query failed to parse: "+pe.getMessage()); + } } - } - return result.toArray(new String[result.size()]); } - throw new UnsupportedOperationException("Cannot list files for URL " - + dirURL); - } + //helper methods follow + //TODO move to masterkey-common + + @SuppressWarnings("rawtypes") + public static String[] getResourceListing(Class clazz, String path) throws + IOException { + URL dirURL = clazz.getClassLoader().getResource(path); + if (dirURL != null && dirURL.getProtocol().equals("file")) { + /* A file path: easy enough */ + try { + return new File(dirURL.toURI()).list(); + } catch (URISyntaxException use) { + throw new UnsupportedOperationException(use); + } + } + + if (dirURL == null) { + /* + * In case of a jar file, we can't actually find a directory. + * Have to assume the same jar as clazz. + */ + String me = clazz.getName().replace(".", "/") + ".class"; + dirURL = clazz.getClassLoader().getResource(me); + } + + if (dirURL.getProtocol().equals("jar")) { + /* A JAR path */ + String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf( + "!")); //strip out only the JAR file + JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8")); + Enumeration entries = jar.entries(); //gives ALL entries in jar + Set result = new HashSet(); //avoid duplicates in case it is a subdirectory + while (entries.hasMoreElements()) { + String name = entries.nextElement().getName(); + if (name.startsWith(path)) { //filter according to the path + String entry = name.substring(path.length()); + int checkSubdir = entry.indexOf("/"); + if (checkSubdir >= 0) { + // if it is a subdirectory, we just return the directory name + entry = entry.substring(0, checkSubdir); + } + result.add(entry); + } + } + return result.toArray(new String[result.size()]); + } + + throw new UnsupportedOperationException("Cannot list files for URL " + + dirURL); + } } \ No newline at end of file