add feature of word list support for CQL->RPN conversion

This commit is contained in:
Jörg Prante 2023-04-14 16:32:00 +02:00
parent 3226ce424b
commit a6e50e7ba5
6 changed files with 43 additions and 74 deletions

View file

@ -1,5 +1,5 @@
group = org.xbib group = org.xbib
name = z3950 name = z3950
version = 5.1.5 version = 5.1.6
org.gradle.warning.mode = ALL org.gradle.warning.mode = ALL

View file

@ -72,7 +72,7 @@ public class JDKZClient implements Client, Closeable {
lock.lock(); lock.lock();
SearchOperation searchOperation = new SearchOperation(berReader, berWriter, SearchOperation searchOperation = new SearchOperation(berReader, berWriter,
builder.resultSetName, builder.databases, builder.host); builder.resultSetName, builder.databases, builder.host);
boolean success = searchOperation.executeCQL(query); boolean success = searchOperation.executeCQL(query, builder.wordListSupported);
if (!success) { if (!success) {
logger.log(Level.WARNING, MessageFormat.format("search was not a success [{0}]", query)); logger.log(Level.WARNING, MessageFormat.format("search was not a success [{0}]", query));
} else { } else {
@ -410,6 +410,8 @@ public class JDKZClient implements Client, Closeable {
private InitListener initListener; private InitListener initListener;
private boolean wordListSupported;
private Builder() { private Builder() {
this.timeout = 5000; this.timeout = 5000;
this.preferredRecordSyntax = "1.2.840.10003.5.10"; // marc21 this.preferredRecordSyntax = "1.2.840.10003.5.10"; // marc21
@ -421,6 +423,7 @@ public class JDKZClient implements Client, Closeable {
this.preferredMessageSize = 10 * 1024 * 1024; this.preferredMessageSize = 10 * 1024 * 1024;
this.implementationName = "Java Z Client"; this.implementationName = "Java Z Client";
this.implementationVersion = "1.00"; this.implementationVersion = "1.00";
this.wordListSupported = true;
} }
public Builder setHost(String host) { public Builder setHost(String host) {
@ -506,6 +509,11 @@ public class JDKZClient implements Client, Closeable {
return this; return this;
} }
public Builder wordListSupported(boolean wordListSupported) {
this.wordListSupported = wordListSupported;
return this;
}
public JDKZClient build() { public JDKZClient build() {
return new JDKZClient(this); return new JDKZClient(this);
} }

View file

@ -1,10 +1,7 @@
package org.xbib.z3950.client.jdk.test; package org.xbib.z3950.client.jdk.test;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -16,15 +13,14 @@ class SWBClientTest {
@Test @Test
void testCQL() { void testCQL() {
String serviceName = "SWB"; //String query = "bib.identifierISSN = 00280836";
String query = "bib.identifierISSN = 00280836"; String query = "bib.any all test";
int from = 1; int from = 1;
int size = 10; int size = 10;
try (JDKZClient client = newZClient(serviceName)) { try (JDKZClient client = newZClient()) {
logger.log(Level.INFO, "executing CQL " + serviceName);
int count = client.searchCQL(query, from, size, null, int count = client.searchCQL(query, from, size, null,
(status, total, returned, elapsedMillis) -> (status, total, returned, elapsedMillis) ->
logger.log(Level.INFO, serviceName + " total results = " + total), logger.log(Level.INFO, "total results = " + total),
record -> logger.log(Level.INFO, "record = " + record), record -> logger.log(Level.INFO, "record = " + record),
() -> logger.log(Level.INFO, "timeout")); () -> logger.log(Level.INFO, "timeout"));
logger.log(Level.INFO, "returned records = " + count); logger.log(Level.INFO, "returned records = " + count);
@ -35,15 +31,13 @@ class SWBClientTest {
@Test @Test
void testPQF() { void testPQF() {
String serviceName = "SWB";
String query = "@attr 1=8 \"00280836\""; String query = "@attr 1=8 \"00280836\"";
int from = 1; int from = 1;
int size = 10; int size = 10;
try (JDKZClient client = newZClient(serviceName)) { try (JDKZClient client = newZClient()) {
logger.log(Level.INFO, "executing PQF " + serviceName);
int count = client.searchPQF(query, from, size, null, int count = client.searchPQF(query, from, size, null,
(status, total, returned, elapsedMillis) -> (status, total, returned, elapsedMillis) ->
logger.log(Level.INFO, serviceName + " status = " + status + " total results = " + total), logger.log(Level.INFO, "status = " + status + " total results = " + total),
record -> logger.log(Level.INFO, "record = " + record.toString(Charset.forName(client.getEncoding()))), record -> logger.log(Level.INFO, "record = " + record.toString(Charset.forName(client.getEncoding()))),
() -> logger.log(Level.WARNING, "timeout")); () -> logger.log(Level.WARNING, "timeout"));
logger.log(Level.INFO, "returned records = " + count); logger.log(Level.INFO, "returned records = " + count);
@ -52,53 +46,19 @@ class SWBClientTest {
} }
} }
private JDKZClient newZClient(String name) throws IOException { private JDKZClient newZClient() {
return newZClient(getProperties(name)); JDKZClient.Builder builder = JDKZClient.builder()
} .setHost("z3950.bsz-bw.de")
.setPort(20210)
private Properties getProperties(String name) throws IOException { .setTimeout(10000L)
Properties properties = new Properties(); .setDatabases(Collections.singletonList("swb_fl"))
try (InputStream inputStream = getClass().getResourceAsStream(name + ".properties")) { .setElementSetName("xf")
properties.load(inputStream); .setPreferredRecordSyntax("marc21")
} .setResultSetName("default")
return properties; .setEncoding("UTF-8")
} .setFormat("Marc21")
.setType("Bibliographic")
private static JDKZClient newZClient(Properties properties) { .wordListSupported(false);
JDKZClient.Builder builder = JDKZClient.builder();
if (properties.containsKey("host")) {
builder.setHost(properties.getProperty("host"));
}
if (properties.containsKey("port")) {
builder.setPort(Integer.parseInt(properties.getProperty("port")));
}
if (properties.containsKey("user")) {
builder.setUser(properties.getProperty("user"));
}
if (properties.containsKey("pass")) {
builder.setPass(properties.getProperty("pass"));
}
if (properties.containsKey("database")) {
builder.setDatabases(Collections.singletonList(properties.getProperty("database")));
}
if (properties.containsKey("elementsetname")) {
builder.setElementSetName(properties.getProperty("elementsetname"));
}
if (properties.containsKey("preferredrecordsyntax")) {
builder.setPreferredRecordSyntax(properties.getProperty("preferredrecordsyntax"));
}
if (properties.containsKey("resultsetname")) {
builder.setResultSetName(properties.getProperty("resultsetname"));
}
if (properties.containsKey("encoding")) {
builder.setEncoding(properties.getProperty("encoding"));
}
if (properties.containsKey("format")) {
builder.setFormat(properties.getProperty("format"));
}
if (properties.containsKey("type")) {
builder.setType(properties.getProperty("type"));
}
return builder.build(); return builder.build();
} }
} }

View file

@ -57,11 +57,13 @@ public final class CQLRPNGenerator implements Visitor {
private RPNQuery rpnQuery; private RPNQuery rpnQuery;
private final boolean wordListSupported;
public CQLRPNGenerator() { public CQLRPNGenerator() {
this(null); this(null, true);
} }
public CQLRPNGenerator(Collection<AttributeElement> attributeElements) { public CQLRPNGenerator(Collection<AttributeElement> attributeElements, boolean wordListSupported) {
this.attributeElements = new Stack<>(); this.attributeElements = new Stack<>();
if (attributeElements != null) { if (attributeElements != null) {
this.attributeElements.addAll(attributeElements); this.attributeElements.addAll(attributeElements);
@ -74,6 +76,7 @@ public final class CQLRPNGenerator implements Visitor {
addContext("bib", ResourceBundle.getBundle("org.xbib.z3950.common.cql.bib-1")); addContext("bib", ResourceBundle.getBundle("org.xbib.z3950.common.cql.bib-1"));
addContext("dc", ResourceBundle.getBundle("org.xbib.z3950.common.cql.dc")); addContext("dc", ResourceBundle.getBundle("org.xbib.z3950.common.cql.dc"));
addContext("gbv", ResourceBundle.getBundle("org.xbib.z3950.common.cql.gbv")); addContext("gbv", ResourceBundle.getBundle("org.xbib.z3950.common.cql.gbv"));
this.wordListSupported = wordListSupported;
} }
public void addContext(String context, ResourceBundle bundle) { public void addContext(String context, ResourceBundle bundle) {
@ -233,13 +236,11 @@ public final class CQLRPNGenerator implements Visitor {
push(attributeElements, createAttributeElement(2, 5)); push(attributeElements, createAttributeElement(2, 5));
case NOT_EQUALS -> case NOT_EQUALS ->
push(attributeElements, createAttributeElement(2, 6)); push(attributeElements, createAttributeElement(2, 6));
case ALL -> { // 4=6 word list case ALL, ANY -> { // 4=6 word list
push(attributeElements, createAttributeElement(2, 3)); push(attributeElements, createAttributeElement(2, 3));
if (wordListSupported) {
replace(attributeElements, createAttributeElement(4, 6)); replace(attributeElements, createAttributeElement(4, 6));
} }
case ANY -> { // 4=104
push(attributeElements, createAttributeElement(2, 3));
replace(attributeElements, createAttributeElement(4, 104));
} }
default -> { default -> {
} }

View file

@ -58,8 +58,8 @@ public class SearchOperation extends AbstractOperation<SearchResponse, SearchReq
return execute(createRPNQueryFromPQF(pqf, charset)); return execute(createRPNQueryFromPQF(pqf, charset));
} }
public boolean executeCQL(String cql) throws IOException { public boolean executeCQL(String cql, boolean wordListSupported) throws IOException {
return execute(createRPNQueryFromCQL(cql)); return execute(createRPNQueryFromCQL(cql, wordListSupported));
} }
public boolean execute(RPNQuery rpn) throws IOException { public boolean execute(RPNQuery rpn) throws IOException {
@ -118,8 +118,8 @@ public class SearchOperation extends AbstractOperation<SearchResponse, SearchReq
return status; return status;
} }
private RPNQuery createRPNQueryFromCQL(String query) { private RPNQuery createRPNQueryFromCQL(String query, boolean wordListSupported) {
CQLRPNGenerator generator = new CQLRPNGenerator(); CQLRPNGenerator generator = new CQLRPNGenerator(null, wordListSupported);
CQLParser parser = new CQLParser(query); CQLParser parser = new CQLParser(query);
parser.parse(); parser.parse();
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);

View file

@ -41,7 +41,7 @@ class CQL2RPNTest {
String cql = "dc.title = \"a phrase\""; String cql = "dc.title = \"a phrase\"";
CQLParser parser = new CQLParser(cql); CQLParser parser = new CQLParser(cql);
parser.parse(); parser.parse();
CQLRPNGenerator generator = new CQLRPNGenerator(Collections.singleton(ae)); CQLRPNGenerator generator = new CQLRPNGenerator(Collections.singleton(ae), true);
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);
String q = generator.getQueryResult().toString(); String q = generator.getQueryResult().toString();
assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 7, attributeValue {numeric 4}}{attributeType 3, attributeValue {numeric 3}}{attributeType 4, attributeValue {numeric 1}}{attributeType 5, attributeValue {numeric 100}}{attributeType 6, attributeValue {numeric 1}}{attributeType 1, attributeValue {numeric 4}}{attributeType 2, attributeValue {numeric 3}}}, term {general \"a phrase\"}}}}}", q); assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 7, attributeValue {numeric 4}}{attributeType 3, attributeValue {numeric 3}}{attributeType 4, attributeValue {numeric 1}}{attributeType 5, attributeValue {numeric 100}}{attributeType 6, attributeValue {numeric 1}}{attributeType 1, attributeValue {numeric 4}}{attributeType 2, attributeValue {numeric 3}}}, term {general \"a phrase\"}}}}}", q);