update netty to 4.1.51, xbib cql to 3.0.2, fix attribute list deriving from CQL search term

This commit is contained in:
Jörg Prante 2020-07-31 10:57:20 +02:00
parent d14cfe0e08
commit 39a962cbdf
8 changed files with 133 additions and 98 deletions

View file

@ -1,8 +1,8 @@
group = org.xbib group = org.xbib
name = z3950 name = z3950
version = 2.2.0 version = 2.2.1
gradle.wrapper.version = 6.4.1 gradle.wrapper.version = 6.4.1
netty.version = 4.1.50.Final netty.version = 4.1.51.Final
xbib-cql.version = 3.0.1 xbib-cql.version = 3.0.2
xbib-bibliographic-character-sets.version = 2.0.0 xbib-bibliographic-character-sets.version = 2.0.0

View file

@ -32,7 +32,6 @@ import org.xbib.z3950.common.v3.Operator;
import org.xbib.z3950.common.v3.RPNQuery; import org.xbib.z3950.common.v3.RPNQuery;
import org.xbib.z3950.common.v3.RPNStructure; import org.xbib.z3950.common.v3.RPNStructure;
import org.xbib.z3950.common.v3.RPNStructureRpnRpnOp; import org.xbib.z3950.common.v3.RPNStructureRpnRpnOp;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@ -49,18 +48,25 @@ public final class CQLRPNGenerator implements Visitor {
/** /**
* Context map. * Context map.
*/ */
private final Map<String, ResourceBundle> contexts = new HashMap<String, ResourceBundle>() { private final Map<String, ResourceBundle> contexts = new HashMap<>() {
private static final long serialVersionUID = 8199395368653216950L; private static final long serialVersionUID = 8199395368653216950L;
{ {
put("cql", ResourceBundle.getBundle("org.xbib.z3950.common.cql.cql"));
put("bib", ResourceBundle.getBundle("org.xbib.z3950.common.cql.bib-1")); put("bib", ResourceBundle.getBundle("org.xbib.z3950.common.cql.bib-1"));
put("dc", ResourceBundle.getBundle("org.xbib.z3950.common.cql.dc")); put("dc", ResourceBundle.getBundle("org.xbib.z3950.common.cql.dc"));
put("gbv", ResourceBundle.getBundle("org.xbib.z3950.common.cql.gbv")); put("gbv", ResourceBundle.getBundle("org.xbib.z3950.common.cql.gbv"));
} }
}; };
private Stack<ASN1Any> result;
private final Stack<AttributeElement> attributeElements;
private final Stack<ASN1Any> result;
private RPNQuery rpnQuery; private RPNQuery rpnQuery;
public CQLRPNGenerator() { public CQLRPNGenerator() {
this.attributeElements = new Stack<>();
this.result = new Stack<>(); this.result = new Stack<>();
} }
@ -80,8 +86,8 @@ public final class CQLRPNGenerator implements Visitor {
this.rpnQuery = new RPNQuery(); this.rpnQuery = new RPNQuery();
rpnQuery.rpn = (RPNStructure) result.pop(); rpnQuery.rpn = (RPNStructure) result.pop();
// Z39.50 BIB-1: urn:oid:1.2.840.10003.3.1 // Z39.50 BIB-1: urn:oid:1.2.840.10003.3.1
rpnQuery.attributeSet = new AttributeSetId(); rpnQuery.attributeSetId = new AttributeSetId();
rpnQuery.attributeSet.value = new ASN1ObjectIdentifier(new int[]{1, 2, 840, 10003, 3, 1}); rpnQuery.attributeSetId.value = new ASN1ObjectIdentifier(new int[]{1, 2, 840, 10003, 3, 1});
} else { } else {
throw new SyntaxException("unable to generate RPN from CQL"); throw new SyntaxException("unable to generate RPN from CQL");
} }
@ -183,15 +189,14 @@ public final class CQLRPNGenerator implements Visitor {
Operand operand = new Operand(); Operand operand = new Operand();
operand.attrTerm = new AttributesPlusTerm(); operand.attrTerm = new AttributesPlusTerm();
operand.attrTerm.term = new org.xbib.z3950.common.v3.Term(); operand.attrTerm.term = new org.xbib.z3950.common.v3.Term();
operand.attrTerm.term.c_general = new ASN1OctetString(node.getTerm().getValue()); ASN1Any any = result.pop();
Stack<AttributeElement> attrs = new Stack<>(); if (any instanceof ASN1OctetString) {
ASN1Any any = !result.isEmpty() && result.peek() instanceof AttributeElement ? result.pop() : null; operand.attrTerm.term.c_general = (ASN1OctetString)any;
while (any != null) { } else {
attrs.push((AttributeElement) any); operand.attrTerm.term.c_general = new ASN1OctetString(node.getTerm().getValue());
any = !result.isEmpty() && result.peek() instanceof AttributeElement ? result.pop() : null;
} }
operand.attrTerm.attributes = new AttributeList(); operand.attrTerm.attributes = new AttributeList();
operand.attrTerm.attributes.value = attrs.toArray(new AttributeElement[attrs.size()]); operand.attrTerm.attributes.value = attributeElements.toArray(new AttributeElement[0]);
RPNStructure rpn = new RPNStructure(); RPNStructure rpn = new RPNStructure();
rpn.c_op = operand; rpn.c_op = operand;
result.push(rpn); result.push(rpn);
@ -202,43 +207,43 @@ public final class CQLRPNGenerator implements Visitor {
if (node.getModifierList() != null) { if (node.getModifierList() != null) {
node.getModifierList().accept(this); node.getModifierList().accept(this);
} }
int t = 2; int attributeType = 2;
int n = 3; int attributeValue = 3;
switch (node.getComparitor()) { switch (node.getComparitor()) {
case LESS: // 2=1 case LESS: // 2=1
n = 1; attributeValue = 1;
break; break;
case LESS_EQUALS: // 2=2 case LESS_EQUALS: // 2=2
n = 2; attributeValue = 2;
break; break;
case EQUALS: // 2=3 case EQUALS: // 2=3
n = 3; attributeValue = 3;
break; break;
case GREATER_EQUALS: // 2=4 case GREATER_EQUALS: // 2=4
n = 4; attributeValue = 4;
break; break;
case GREATER: // 2=5 case GREATER: // 2=5
n = 5; attributeValue = 5;
break; break;
case NOT_EQUALS: // 2=6 case NOT_EQUALS: // 2=6
n = 6; attributeValue = 6;
break; break;
case ALL: // 4=6 case ALL: // 4=6
t = 4; attributeType = 4;
n = 6; attributeValue = 6;
break; break;
case ANY: // 4=105 case ANY: // 4=105
t = 4; attributeType = 4;
n = 104; attributeValue = 104;
break; break;
default: default:
break; break;
} }
if (n != 3) { if (attributeValue != 3) {
AttributeElement ae = new AttributeElement(); AttributeElement ae = new AttributeElement();
ae.attributeType = new ASN1Integer(t); ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue(); ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(n); ae.attributeValue.numeric = new ASN1Integer(attributeValue);
result.push(ae); result.push(ae);
} }
} }
@ -261,29 +266,9 @@ public final class CQLRPNGenerator implements Visitor {
} }
@Override @Override
public void visit(Term node) { public void visit(Term term) {
int t = 5; // the value
int n = 100; ASN1OctetString s = transformTerm(term);
// check for '*'
String v = node.getValue();
if (v.endsWith("*")) {
if (v.startsWith("*")) {
n = 3;
} else {
n = 1;
}
} else if (v.startsWith("*")) {
n = 2;
}
if (n != 100) {
AttributeElement ae = new AttributeElement();
ae.attributeType = new ASN1Integer(t);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(n);
result.push(ae);
v = v.replaceAll("\\*", "");
}
ASN1OctetString s = new ASN1OctetString(v);
result.push(s); result.push(s);
} }
@ -298,18 +283,18 @@ public final class CQLRPNGenerator implements Visitor {
} }
@Override @Override
public void visit(Index node) { public void visit(Index index) {
String context = node.getContext(); String context = index.getContext();
if (context == null) { if (context == null) {
context = "dc"; // default context context = "dc"; // default context
} }
int t = 1; int attributeType = 1; // use attribute set: bib-1 = 1
int n = getUseAttr(context, node.getName()); int attributeValue = getUseAttr(context, index.getName());
AttributeElement ae = new AttributeElement(); AttributeElement ae = new AttributeElement();
ae.attributeType = new ASN1Integer(t); ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue(); ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(n); ae.attributeValue.numeric = new ASN1Integer(attributeValue);
result.push(ae); attributeElements.push(ae);
} }
private int getUseAttr(String context, String attrName) { private int getUseAttr(String context, String attrName) {
@ -319,4 +304,63 @@ public final class CQLRPNGenerator implements Visitor {
throw new SyntaxException("unknown use attribute '" + attrName + "' for context " + context, e); throw new SyntaxException("unknown use attribute '" + attrName + "' for context " + context, e);
} }
} }
private ASN1OctetString transformTerm(Term term) {
String v = term.getValue();
// let's derive attributes from the search term
// relation attribute = 2
int attributeType = 2;
int attributeValue = 3; // equal = 3
AttributeElement ae = new AttributeElement();
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
// position attribute = 3
attributeType = 3;
attributeValue = 3; // any position = 3
ae = new AttributeElement();
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
// structure attribute = 4
attributeType = 4;
attributeValue = 2; // word = 2
if (v.startsWith("\"") && v.endsWith("\"")) {
attributeValue = 1; // phrase
v = v.substring(1, v.length()-1);
}
ae = new AttributeElement();
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
// truncation attribute = 5
attributeType = 5;
attributeValue = 100; // do not truncate = 5
if (v.endsWith("*")) {
if (v.startsWith("*")) {
attributeValue = 3; // Left and right truncation = 3
v = v.substring(1, v.length() - 1);
} else {
attributeValue = 1; // Right truncation = 1
v = v.substring(0, v.length() - 1);
}
} else if (v.startsWith("*")) {
attributeValue = 2; // Left truncation = 2
v = v.substring(1);
}
ae = new AttributeElement();
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
return new ASN1OctetString(v);
}
} }

View file

@ -42,8 +42,8 @@ public class PQFRPNGenerator implements Visitor {
rpnQuery.rpn = (RPNStructure) result.pop(); rpnQuery.rpn = (RPNStructure) result.pop();
if (pqf.getAttrSet() == null) { if (pqf.getAttrSet() == null) {
// Z39.50 BIB-1: urn:oid:1.2.840.10003.3.1 // Z39.50 BIB-1: urn:oid:1.2.840.10003.3.1
rpnQuery.attributeSet = new AttributeSetId(); rpnQuery.attributeSetId = new AttributeSetId();
rpnQuery.attributeSet.value = new ASN1ObjectIdentifier(new int[]{1, 2, 840, 10003, 3, 1}); rpnQuery.attributeSetId.value = new ASN1ObjectIdentifier(new int[]{1, 2, 840, 10003, 3, 1});
} }
} else { } else {
throw new SyntaxException("no valid PQF found"); throw new SyntaxException("no valid PQF found");

View file

@ -89,7 +89,7 @@ public final class AttributeList extends ASN1Any {
*/ */
@Override @Override
public BEREncoding berEncode(int tagType, int tag) throws ASN1Exception { public BEREncoding berEncode(int tagType, int tag) throws ASN1Exception {
BEREncoding fields[] = new BERConstructed[value.length]; BEREncoding[] fields = new BERConstructed[value.length];
int p; int p;
for (p = 0; p < value.length; p++) { for (p = 0; p < value.length; p++) {
fields[p] = value[p].berEncode(); fields[p] = value[p].berEncode();

View file

@ -19,7 +19,9 @@ import org.xbib.asn1.BEREncoding;
public final class Operand extends ASN1Any { public final class Operand extends ASN1Any {
public AttributesPlusTerm attrTerm; public AttributesPlusTerm attrTerm;
public ResultSetId resultSet; public ResultSetId resultSet;
public ResultSetPlusAttributes resultAttr; public ResultSetPlusAttributes resultAttr;
public Operand() { public Operand() {
@ -50,11 +52,9 @@ public final class Operand extends ASN1Any {
@Override @Override
public void berDecode(BEREncoding ber, boolean checkTag) throws ASN1Exception { public void berDecode(BEREncoding ber, boolean checkTag) throws ASN1Exception {
// Null out all choices // Null out all choices
attrTerm = null; attrTerm = null;
resultSet = null; resultSet = null;
resultAttr = null; resultAttr = null;
// Try choice attrTerm // Try choice attrTerm
try { try {
attrTerm = new AttributesPlusTerm(ber, checkTag); attrTerm = new AttributesPlusTerm(ber, checkTag);
@ -62,7 +62,6 @@ public final class Operand extends ASN1Any {
} catch (ASN1Exception e) { } catch (ASN1Exception e) {
// failed to decode, continue on // failed to decode, continue on
} }
// Try choice resultSet // Try choice resultSet
try { try {
resultSet = new ResultSetId(ber, checkTag); resultSet = new ResultSetId(ber, checkTag);
@ -70,7 +69,6 @@ public final class Operand extends ASN1Any {
} catch (ASN1Exception e) { } catch (ASN1Exception e) {
// failed to decode, continue on // failed to decode, continue on
} }
// Try choice resultAttr // Try choice resultAttr
try { try {
resultAttr = new ResultSetPlusAttributes(ber, checkTag); resultAttr = new ResultSetPlusAttributes(ber, checkTag);
@ -78,7 +76,6 @@ public final class Operand extends ASN1Any {
} catch (ASN1Exception e) { } catch (ASN1Exception e) {
// failed to decode, continue on // failed to decode, continue on
} }
throw new ASN1Exception("bad BER encoding: choice not matched"); throw new ASN1Exception("bad BER encoding: choice not matched");
} }
@ -91,12 +88,10 @@ public final class Operand extends ASN1Any {
@Override @Override
public BEREncoding berEncode() throws ASN1Exception { public BEREncoding berEncode() throws ASN1Exception {
BEREncoding chosen = null; BEREncoding chosen = null;
// Encoding choice: c_attrTerm // Encoding choice: c_attrTerm
if (attrTerm != null) { if (attrTerm != null) {
chosen = attrTerm.berEncode(); chosen = attrTerm.berEncode();
} }
// Encoding choice: c_resultSet // Encoding choice: c_resultSet
if (resultSet != null) { if (resultSet != null) {
if (chosen != null) { if (chosen != null) {

View file

@ -19,7 +19,8 @@ import org.xbib.asn1.BEREncoding;
*/ */
public final class RPNQuery extends ASN1Any { public final class RPNQuery extends ASN1Any {
public AttributeSetId attributeSet; public AttributeSetId attributeSetId;
public RPNStructure rpn; public RPNStructure rpn;
/** /**
@ -65,7 +66,7 @@ public final class RPNQuery extends ASN1Any {
throw new ASN1Exception("incomplete"); throw new ASN1Exception("incomplete");
} }
p = berConstructed.elementAt(part); p = berConstructed.elementAt(part);
attributeSet = new AttributeSetId(p, true); attributeSetId = new AttributeSetId(p, true);
part++; part++;
if (numParts <= part) { if (numParts <= part) {
throw new ASN1Exception("incomplete"); throw new ASN1Exception("incomplete");
@ -100,9 +101,9 @@ public final class RPNQuery extends ASN1Any {
@Override @Override
public BEREncoding berEncode(int tagType, int tag) throws ASN1Exception { public BEREncoding berEncode(int tagType, int tag) throws ASN1Exception {
int numFields = 2; int numFields = 2;
BEREncoding fields[] = new BEREncoding[numFields]; BEREncoding[] fields = new BEREncoding[numFields];
int x = 0; int x = 0;
fields[x++] = attributeSet.berEncode(); fields[x++] = attributeSetId.berEncode();
fields[x] = rpn.berEncode(); fields[x] = rpn.berEncode();
return new BERConstructed(tagType, tag, fields); return new BERConstructed(tagType, tag, fields);
} }
@ -113,17 +114,6 @@ public final class RPNQuery extends ASN1Any {
*/ */
@Override @Override
public String toString() { public String toString() {
StringBuilder str = new StringBuilder("{"); return "{" + "attributeSetId " + attributeSetId + ", " + "rpn " + rpn + "}";
int outputted = 0;
str.append("attributeSet ");
str.append(attributeSet);
outputted++;
if (0 < outputted) {
str.append(", ");
}
str.append("rpn ");
str.append(rpn);
str.append("}");
return str.toString();
} }
} }

View file

@ -19,6 +19,7 @@ import org.xbib.asn1.BEREncoding;
public final class RPNStructure extends ASN1Any { public final class RPNStructure extends ASN1Any {
public Operand c_op; public Operand c_op;
public RPNStructureRpnRpnOp c_rpnRpnOp; public RPNStructureRpnRpnOp c_rpnRpnOp;
/** /**
@ -86,16 +87,13 @@ public final class RPNStructure extends ASN1Any {
@Override @Override
public BEREncoding berEncode() throws ASN1Exception { public BEREncoding berEncode() throws ASN1Exception {
BEREncoding chosen = null; BEREncoding chosen = null;
BEREncoding[] enc;
BEREncoding enc[];
// Encoding choice: c_op // Encoding choice: c_op
if (c_op != null) { if (c_op != null) {
enc = new BEREncoding[1]; enc = new BEREncoding[1];
enc[0] = c_op.berEncode(); enc[0] = c_op.berEncode();
chosen = new BERConstructed(BEREncoding.CONTEXT_SPECIFIC_TAG, 0, enc); chosen = new BERConstructed(BEREncoding.CONTEXT_SPECIFIC_TAG, 0, enc);
} }
// Encoding choice: c_rpnRpnOp // Encoding choice: c_rpnRpnOp
if (c_rpnRpnOp != null) { if (c_rpnRpnOp != null) {
if (chosen != null) { if (chosen != null) {
@ -103,7 +101,6 @@ public final class RPNStructure extends ASN1Any {
} }
chosen = c_rpnRpnOp.berEncode(BEREncoding.CONTEXT_SPECIFIC_TAG, 1); chosen = c_rpnRpnOp.berEncode(BEREncoding.CONTEXT_SPECIFIC_TAG, 1);
} }
// Check for error of having none of the choices set // Check for error of having none of the choices set
if (chosen == null) { if (chosen == null) {
throw new ASN1Exception("CHOICE not set"); throw new ASN1Exception("CHOICE not set");

View file

@ -1,21 +1,30 @@
package org.xbib.z3950.common.cql; package org.xbib.z3950.common.cql;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.cql.CQLParser; import org.xbib.cql.CQLParser;
/**
*
*/
class CQL2RPNTest { class CQL2RPNTest {
@Test @Test
void testCQL2RPN() { void testDublinCoreContext() {
String cql = "dc.title = Test"; String cql = "dc.title = Test";
CQLParser parser = new CQLParser(cql); CQLParser parser = new CQLParser(cql);
parser.parse(); parser.parse();
CQLRPNGenerator generator = new CQLRPNGenerator(); CQLRPNGenerator generator = new CQLRPNGenerator();
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);
String q = generator.getQueryResult().toString(); String q = generator.getQueryResult().toString();
System.err.println("cql2rpn = " + q); assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 2, attributeValue {numeric 3}}{attributeType 3, attributeValue {numeric 3}}{attributeType 4, attributeValue {numeric 2}}{attributeType 5, attributeValue {numeric 100}}{attributeType 1, attributeValue {numeric 4}}}, term {general \"Test\"}}}}}", q);
}
@Test
void testPhrase() {
String cql = "dc.title = \"a phrase\"";
CQLParser parser = new CQLParser(cql);
parser.parse();
CQLRPNGenerator generator = new CQLRPNGenerator();
parser.getCQLQuery().accept(generator);
String q = generator.getQueryResult().toString();
assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 2, attributeValue {numeric 3}}{attributeType 3, attributeValue {numeric 3}}{attributeType 4, attributeValue {numeric 1}}{attributeType 5, attributeValue {numeric 100}}{attributeType 1, attributeValue {numeric 4}}}, term {general \"a phrase\"}}}}}", q);
} }
} }