new client api subproject

This commit is contained in:
Jörg Prante 2020-08-05 11:42:11 +02:00
parent 39a962cbdf
commit 9ae052559b
20 changed files with 279 additions and 145 deletions

View file

@ -1,6 +1,7 @@
include 'z3950-asn1' include 'z3950-asn1'
include 'z3950-api' include 'z3950-api'
include 'z3950-common' include 'z3950-common'
include 'z3950-client' include 'z3950-client-api'
include 'z3950-client-jdk'
include 'z3950-client-netty' include 'z3950-client-netty'
include 'z3950-sru' include 'z3950-sru'

View file

@ -0,0 +1,3 @@
dependencies {
api project(':z3950-common')
}

View file

@ -0,0 +1,4 @@
module org.xbib.z3950lib.client.api {
exports org.xbib.z3950.client.api;
requires transitive org.xbib.z3950lib.common;
}

View file

@ -1,5 +1,8 @@
package org.xbib.z3950.api; package org.xbib.z3950.client.api;
import org.xbib.z3950.api.RecordListener;
import org.xbib.z3950.api.ScanListener;
import org.xbib.z3950.api.SearchListener;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -7,8 +10,8 @@ import java.util.List;
public interface Client extends Closeable { public interface Client extends Closeable {
int searchCQL(String query, int offset, int length, int searchCQL(String query, int offset, int length,
SearchListener searchListener, SearchListener searchListener,
RecordListener recordListener) throws IOException; RecordListener recordListener) throws IOException;
int searchPQF(String query, int offset, int length, int searchPQF(String query, int offset, int length,
SearchListener searchListener, SearchListener searchListener,
@ -40,5 +43,4 @@ public interface Client extends Closeable {
String getType(); String getType();
List<String> getDatabases(); List<String> getDatabases();
} }

View file

@ -1,4 +1,4 @@
package org.xbib.z3950.api; package org.xbib.z3950.client.api;
/** /**
* Client provider. * Client provider.

View file

@ -1,4 +1,4 @@
dependencies { dependencies {
api project(':z3950-common') api project(':z3950-client-api')
testImplementation "org.xbib:bibliographic-character-sets:${project.property('xbib-bibliographic-character-sets.version')}" testImplementation "org.xbib:bibliographic-character-sets:${project.property('xbib-bibliographic-character-sets.version')}"
} }

View file

@ -0,0 +1,5 @@
module org.xbib.z3950lib.client.jdk {
exports org.xbib.z3950.client.jdk;
requires transitive org.xbib.z3950lib.client.api;
requires java.logging;
}

View file

@ -1,4 +1,4 @@
package org.xbib.z3950.client; package org.xbib.z3950.client.jdk;
import org.xbib.asn1.io.InputStreamBERReader; import org.xbib.asn1.io.InputStreamBERReader;
import org.xbib.asn1.io.OutputStreamBERWriter; import org.xbib.asn1.io.OutputStreamBERWriter;
@ -7,14 +7,14 @@ import org.xbib.z3950.common.operations.InitOperation;
import org.xbib.z3950.common.operations.PresentOperation; import org.xbib.z3950.common.operations.PresentOperation;
import org.xbib.z3950.common.operations.ScanOperation; import org.xbib.z3950.common.operations.ScanOperation;
import org.xbib.z3950.common.operations.SearchOperation; import org.xbib.z3950.common.operations.SearchOperation;
import org.xbib.z3950.api.Client; import org.xbib.z3950.client.api.Client;
import org.xbib.z3950.api.InitListener; import org.xbib.z3950.api.InitListener;
import org.xbib.z3950.api.RecordListener; import org.xbib.z3950.api.RecordListener;
import org.xbib.z3950.api.ScanListener; import org.xbib.z3950.api.ScanListener;
import org.xbib.z3950.api.SearchListener; import org.xbib.z3950.api.SearchListener;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -32,9 +32,9 @@ import java.util.logging.Logger;
/** /**
* Default Z client. * Default Z client.
*/ */
public class DefaultClient implements Client { public class JDKZClient implements Client, Closeable {
private static final Logger logger = Logger.getLogger(DefaultClient.class.getName()); private static final Logger logger = Logger.getLogger(JDKZClient.class.getName());
private final String host; private final String host;
@ -72,16 +72,16 @@ public class DefaultClient implements Client {
private OutputStreamBERWriter berWriter; private OutputStreamBERWriter berWriter;
private DefaultClient(String host, int port, String user, String pass, long timeout, private JDKZClient(String host, int port, String user, String pass, long timeout,
String preferredRecordSyntax, String preferredRecordSyntax,
String resultSetName, String resultSetName,
String elementSetName, String elementSetName,
String encoding, String encoding,
String format, String format,
String type, String type,
List<String> databases, List<String> databases,
Integer preferredMessageSize, Integer preferredMessageSize,
InitListener initListener) { InitListener initListener) {
this.host = host; this.host = host;
this.port = port; this.port = port;
this.user = user; this.user = user;
@ -99,39 +99,6 @@ public class DefaultClient implements Client {
this.lock = new ReentrantLock(); this.lock = new ReentrantLock();
} }
@Override
public void close() {
if (isConnected()) {
try {
lock.lock();
try {
sendClose(0);
} catch (IOException e) {
logger.log(Level.WARNING, "while attempting to send close for close connection: " + e.getMessage(), e);
}
try {
berReader.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error attempting to close src: " + e.getMessage(), e);
}
try {
berWriter.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error attempting to close dest: " + e.getMessage(), e);
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
logger.log(Level.WARNING, "error attempting to close socket: " + e.getMessage(), e);
}
} finally {
lock.unlock();
}
}
}
@Override @Override
public int searchCQL(String query, int offset, int length, public int searchCQL(String query, int offset, int length,
SearchListener searchListener, SearchListener searchListener,
@ -288,8 +255,66 @@ public class DefaultClient implements Client {
return databases; return databases;
} }
private void connect() throws IOException { public void connect() throws IOException {
try {
lock.lock();
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port), (int) timeout);
socket.setSoTimeout((int) timeout * 1000);
this.socket = socket;
InputStream src = new BufferedInputStream(socket.getInputStream());
OutputStream dest = new BufferedOutputStream(socket.getOutputStream());
this.berReader = new InputStreamBERReader(src);
this.berWriter = new OutputStreamBERWriter(dest);
InitOperation initOperation = new InitOperation(berReader, berWriter, user, pass);
if (initOperation.execute(preferredMessageSize, initListener)) {
throw new IOException("could not initiate connection");
}
logger.log(Level.INFO, initOperation.getTargetInfo());
} finally {
lock.unlock();
}
}
public void disconnect() throws IOException {
try {
lock.lock();
try {
sendClose(0);
} catch (IOException e) {
logger.log(Level.WARNING, "while attempting to send close for close connection: " + e.getMessage(), e);
}
try {
berReader.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error attempting to close src: " + e.getMessage(), e);
}
try {
berWriter.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error attempting to close dest: " + e.getMessage(), e);
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
logger.log(Level.WARNING, "error attempting to close socket: " + e.getMessage(), e);
}
} finally {
lock.unlock();
}
}
@Override
public void close() throws IOException {
if (isConnected()) {
disconnect();
}
}
public static Builder builder() {
return new Builder();
} }
private boolean isConnected() { private boolean isConnected() {
@ -298,31 +323,10 @@ public class DefaultClient implements Client {
private void ensureConnected() throws IOException { private void ensureConnected() throws IOException {
if (!isConnected()) { if (!isConnected()) {
try { connect();
lock.lock();
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port), (int) timeout);
socket.setSoTimeout((int) timeout * 1000);
this.socket = socket;
InputStream src = new BufferedInputStream(socket.getInputStream());
OutputStream dest = new BufferedOutputStream(socket.getOutputStream());
this.berReader = new InputStreamBERReader(src);
this.berWriter = new OutputStreamBERWriter(dest);
InitOperation initOperation = new InitOperation(berReader, berWriter, user, pass);
if (initOperation.execute(preferredMessageSize, initListener)) {
throw new IOException("could not initiate connection");
}
logger.log(Level.INFO, initOperation.getTargetInfo());
} finally {
lock.unlock();
}
} }
} }
public static Builder builder() {
return new Builder();
}
/** /**
* Send a close request to the server. * Send a close request to the server.
* *
@ -454,8 +458,8 @@ public class DefaultClient implements Client {
return this; return this;
} }
public DefaultClient build() { public JDKZClient build() {
return new DefaultClient(host, port, user, pass, timeout, return new JDKZClient(host, port, user, pass, timeout,
preferredRecordSyntax, preferredRecordSyntax,
resultSetName, resultSetName,
elementSetName, elementSetName,

View file

@ -1,7 +1,7 @@
package org.xbib.z3950.client.test; package org.xbib.z3950.client.jdk.test;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.z3950.client.DefaultClient; import org.xbib.z3950.client.jdk.JDKZClient;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -25,7 +25,7 @@ class DefaultClientTest {
String query = "bib.identifierISSN = 00280836"; String query = "bib.identifierISSN = 00280836";
int from = 1; int from = 1;
int size = 10; int size = 10;
try (DefaultClient client = newZClient(serviceName)) { try (JDKZClient client = newZClient(serviceName)) {
logger.log(Level.INFO, "executing CQL " + serviceName); logger.log(Level.INFO, "executing CQL " + serviceName);
int count = client.searchCQL(query, from, size, int count = client.searchCQL(query, from, size,
(status, total, returned, elapsedMillis) -> (status, total, returned, elapsedMillis) ->
@ -44,7 +44,7 @@ class DefaultClientTest {
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 (DefaultClient client = newZClient(serviceName)) { try (JDKZClient client = newZClient(serviceName)) {
logger.log(Level.INFO, "executing PQF " + serviceName); logger.log(Level.INFO, "executing PQF " + serviceName);
int count = client.searchPQF(query, from, size, int count = client.searchPQF(query, from, size,
(status, total, returned, elapsedMillis) -> (status, total, returned, elapsedMillis) ->
@ -57,7 +57,7 @@ class DefaultClientTest {
} }
} }
private DefaultClient newZClient(String name) throws IOException { private JDKZClient newZClient(String name) throws IOException {
return newZClient(getProperties(name)); return newZClient(getProperties(name));
} }
@ -69,8 +69,8 @@ class DefaultClientTest {
return properties; return properties;
} }
private static DefaultClient newZClient(Properties properties) { private static JDKZClient newZClient(Properties properties) {
DefaultClient.Builder builder = DefaultClient.builder(); JDKZClient.Builder builder = JDKZClient.builder();
if (properties.containsKey("host")) { if (properties.containsKey("host")) {
builder.setHost(properties.getProperty("host")); builder.setHost(properties.getProperty("host"));
} }

View file

@ -1,7 +1,7 @@
package org.xbib.z3950.client.test; package org.xbib.z3950.client.jdk.test;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.z3950.client.DefaultClient; import org.xbib.z3950.client.jdk.JDKZClient;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -25,7 +25,7 @@ class GBVZClientTest {
String query = "@attr 1=4 linux"; String query = "@attr 1=4 linux";
int from = 1; int from = 1;
int size = 10; int size = 10;
try (DefaultClient client = newZClient("GBV")) { try (JDKZClient client = newZClient("GBV")) {
logger.log(Level.INFO, "executing PQF " + query); logger.log(Level.INFO, "executing PQF " + query);
int count = client.searchPQF(query, from, size, int count = client.searchPQF(query, from, size,
(status, total, returned, elapsedMillis) -> (status, total, returned, elapsedMillis) ->
@ -43,7 +43,7 @@ class GBVZClientTest {
String query = "bib.controlNumberZDB = 1413423-8"; String query = "bib.controlNumberZDB = 1413423-8";
int from = 1; int from = 1;
int size = 2; int size = 2;
try (DefaultClient client = newZClient(serviceName)) { try (JDKZClient client = newZClient(serviceName)) {
logger.log(Level.INFO, "executing CQL " + query); logger.log(Level.INFO, "executing CQL " + query);
int count = client.searchCQL(query, from, size, int count = client.searchCQL(query, from, size,
(status, total, returned, elapsedMillis) -> (status, total, returned, elapsedMillis) ->
@ -57,7 +57,7 @@ class GBVZClientTest {
} }
private DefaultClient newZClient(String name) throws IOException { private JDKZClient newZClient(String name) throws IOException {
return newZClient(getProperties(name)); return newZClient(getProperties(name));
} }
@ -69,8 +69,8 @@ class GBVZClientTest {
return properties; return properties;
} }
private static DefaultClient newZClient(Properties properties) { private static JDKZClient newZClient(Properties properties) {
DefaultClient.Builder builder = DefaultClient.builder(); JDKZClient.Builder builder = JDKZClient.builder();
if (properties.containsKey("host")) { if (properties.containsKey("host")) {
builder.setHost(properties.getProperty("host")); builder.setHost(properties.getProperty("host"));
} }

View file

@ -1,9 +1,9 @@
package org.xbib.z3950.client.test; package org.xbib.z3950.client.jdk.test;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.z3950.common.exceptions.MessageSizeTooSmallException; import org.xbib.z3950.common.exceptions.MessageSizeTooSmallException;
import org.xbib.z3950.common.exceptions.NoRecordsReturnedException; import org.xbib.z3950.common.exceptions.NoRecordsReturnedException;
import org.xbib.z3950.client.DefaultClient; import org.xbib.z3950.client.jdk.JDKZClient;
import java.util.Collections; import java.util.Collections;
import java.util.logging.Level; import java.util.logging.Level;
@ -27,7 +27,7 @@ class SearchTest {
int from = 1; int from = 1;
int length = 1; int length = 1;
try { try {
DefaultClient client = DefaultClient.builder() JDKZClient client = JDKZClient.builder()
.setHost(host) .setHost(host)
.setPort(port) .setPort(port)
.setDatabases(Collections.singletonList(database)) .setDatabases(Collections.singletonList(database))

View file

@ -1,5 +1,8 @@
dependencies { dependencies {
api project(':z3950-common') api project(':z3950-client-api')
implementation "io.netty:netty-buffer:${project.property('netty.version')}"
implementation "io.netty:netty-common:${project.property('netty.version')}"
implementation "io.netty:netty-handler:${project.property('netty.version')}" implementation "io.netty:netty-handler:${project.property('netty.version')}"
implementation "io.netty:netty-transport:${project.property('netty.version')}" implementation "io.netty:netty-transport:${project.property('netty.version')}"
testImplementation "org.xbib:bibliographic-character-sets:${project.property('xbib-bibliographic-character-sets.version')}"
} }

View file

@ -1,6 +1,9 @@
module org.xbib.z3950lib.client.netty { module org.xbib.z3950lib.client.netty {
exports org.xbib.z3950.client.netty; exports org.xbib.z3950.client.netty;
requires transitive org.xbib.z3950lib.common; requires transitive org.xbib.z3950lib.client.api;
requires io.netty.buffer;
requires io.netty.common;
requires io.netty.handler; requires io.netty.handler;
requires io.netty.transport; requires io.netty.transport;
requires java.logging;
} }

View file

@ -13,12 +13,19 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import org.xbib.z3950.api.RecordListener;
import org.xbib.z3950.api.ScanListener;
import org.xbib.z3950.api.SearchListener;
import org.xbib.z3950.client.api.Client;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.List;
/** /**
* *
*/ */
public class NettyZClient { public class NettyZClient implements Client, Closeable {
private final EventLoopGroup group; private final EventLoopGroup group;
private final Bootstrap clientBootstrap; private final Bootstrap clientBootstrap;
@ -46,6 +53,86 @@ public class NettyZClient {
group.shutdownGracefully().sync(); group.shutdownGracefully().sync();
} }
@Override
public void close() throws IOException {
}
@Override
public int searchCQL(String query, int offset, int length, SearchListener searchListener, RecordListener recordListener) throws IOException {
return 0;
}
@Override
public int searchPQF(String query, int offset, int length, SearchListener searchListener, RecordListener recordListener) throws IOException {
return 0;
}
@Override
public void scanPQF(String query, int nTerms, int step, int position, ScanListener scanListener) throws IOException {
}
@Override
public String getHost() {
return null;
}
@Override
public int getPort() {
return 0;
}
@Override
public String getUser() {
return null;
}
@Override
public String getPass() {
return null;
}
@Override
public long getTimeout() {
return 0;
}
@Override
public String getPreferredRecordSyntax() {
return null;
}
@Override
public String getResultSetName() {
return null;
}
@Override
public String getElementSetName() {
return null;
}
@Override
public String getEncoding() {
return null;
}
@Override
public String getFormat() {
return null;
}
@Override
public String getType() {
return null;
}
@Override
public List<String> getDatabases() {
return null;
}
class Handler extends SimpleChannelInboundHandler<ByteBuf> { class Handler extends SimpleChannelInboundHandler<ByteBuf> {
@Override @Override

View file

@ -1,5 +0,0 @@
module org.xbib.z3950lib.client {
exports org.xbib.z3950.client;
requires transitive org.xbib.z3950lib.common;
requires java.logging;
}

View file

@ -32,6 +32,7 @@ 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.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@ -70,6 +71,12 @@ public final class CQLRPNGenerator implements Visitor {
this.result = new Stack<>(); this.result = new Stack<>();
} }
public CQLRPNGenerator(Collection<AttributeElement> attributeElements) {
this.attributeElements = new Stack<>();
this.attributeElements.addAll(attributeElements);
this.result = new Stack<>();
}
public RPNQuery getQueryResult() { public RPNQuery getQueryResult() {
return rpnQuery; return rpnQuery;
} }
@ -196,7 +203,8 @@ public final class CQLRPNGenerator implements Visitor {
operand.attrTerm.term.c_general = new ASN1OctetString(node.getTerm().getValue()); operand.attrTerm.term.c_general = new ASN1OctetString(node.getTerm().getValue());
} }
operand.attrTerm.attributes = new AttributeList(); operand.attrTerm.attributes = new AttributeList();
operand.attrTerm.attributes.value = attributeElements.toArray(new AttributeElement[0]); operand.attrTerm.attributes.value = attributeElements.stream()
.filter(ae -> ae.attributeValue != null).toArray(AttributeElement[]::new);
RPNStructure rpn = new RPNStructure(); RPNStructure rpn = new RPNStructure();
rpn.c_op = operand; rpn.c_op = operand;
result.push(rpn); result.push(rpn);
@ -307,25 +315,17 @@ public final class CQLRPNGenerator implements Visitor {
private ASN1OctetString transformTerm(Term term) { private ASN1OctetString transformTerm(Term term) {
String v = term.getValue(); String v = term.getValue();
// let's derive attributes from the search term // let's derive attributes from the search term syntax
// relation attribute = 2 // relation attribute = 2
int attributeType = 2; int attributeType = 2;
int attributeValue = 3; // equal = 3 int attributeValue = 3; // equal = 3
AttributeElement ae = new AttributeElement(); push(attributeElements, createAttributeElement(attributeType, attributeValue));
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
// position attribute = 3 // position attribute = 3
attributeType = 3; //attributeType = 3;
attributeValue = 3; // any position = 3 // attributeValue = 3; // any position = 3
ae = new AttributeElement(); //push(attributeElements, createAttributeElement(attributeType, attributeValue));
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
// structure attribute = 4 // structure attribute = 4
attributeType = 4; attributeType = 4;
@ -334,11 +334,7 @@ public final class CQLRPNGenerator implements Visitor {
attributeValue = 1; // phrase attributeValue = 1; // phrase
v = v.substring(1, v.length()-1); v = v.substring(1, v.length()-1);
} }
ae = new AttributeElement(); push(attributeElements, createAttributeElement(attributeType, attributeValue));
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
// truncation attribute = 5 // truncation attribute = 5
attributeType = 5; attributeType = 5;
@ -355,12 +351,27 @@ public final class CQLRPNGenerator implements Visitor {
attributeValue = 2; // Left truncation = 2 attributeValue = 2; // Left truncation = 2
v = v.substring(1); v = v.substring(1);
} }
ae = new AttributeElement(); push(attributeElements, createAttributeElement(attributeType, attributeValue));
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
attributeElements.push(ae);
return new ASN1OctetString(v); return new ASN1OctetString(v);
} }
private static void push(Stack<AttributeElement> stack, AttributeElement attributeElement) {
if (attributeElement != null) {
if (!stack.contains(attributeElement)) {
stack.push(attributeElement);
}
}
}
private static AttributeElement createAttributeElement(Integer attributeType, Integer attributeValue) {
if (attributeType != null && attributeValue != null) {
AttributeElement ae = new AttributeElement();
ae.attributeType = new ASN1Integer(attributeType);
ae.attributeValue = new AttributeElementAttributeValue();
ae.attributeValue.numeric = new ASN1Integer(attributeValue);
return ae;
} else {
return null;
}
}
} }

View file

@ -120,7 +120,7 @@ public final class AccessControlRequest extends ASN1Any {
if (sOtherInfo != null) { if (sOtherInfo != null) {
numFields++; numFields++;
} }
BEREncoding fields[] = new BEREncoding[numFields]; BEREncoding[] fields = new BEREncoding[numFields];
int x = 0; int x = 0;
if (sReferenceId != null) { if (sReferenceId != null) {
fields[x++] = sReferenceId.berEncode(); fields[x++] = sReferenceId.berEncode();
@ -149,11 +149,8 @@ public final class AccessControlRequest extends ASN1Any {
} }
str.append("securityChallenge "); str.append("securityChallenge ");
str.append(sSecurityChallenge); str.append(sSecurityChallenge);
outputted++;
if (sOtherInfo != null) { if (sOtherInfo != null) {
if (0 < outputted) { str.append(", ");
str.append(", ");
}
str.append("otherInfo "); str.append("otherInfo ");
str.append(sOtherInfo); str.append(sOtherInfo);
} }

View file

@ -82,7 +82,7 @@ public final class AccessControlRequestSecurityChallenge extends ASN1Any {
@Override @Override
public BEREncoding berEncode() throws ASN1Exception { public BEREncoding berEncode() throws ASN1Exception {
BEREncoding chosen = null; BEREncoding chosen = null;
BEREncoding enc[]; BEREncoding[] enc;
if (cSimpleForm != null) { if (cSimpleForm != null) {
chosen = cSimpleForm.berEncode(BEREncoding.CONTEXT_SPECIFIC_TAG, 37); chosen = cSimpleForm.berEncode(BEREncoding.CONTEXT_SPECIFIC_TAG, 37);
} }

View file

@ -19,7 +19,7 @@ import org.xbib.asn1.BEREncoding;
* } * }
* </pre> * </pre>
*/ */
public final class AttributeElement extends ASN1Any { public final class AttributeElement extends ASN1Any implements Comparable<AttributeElement> {
public AttributeSetId attributeSetId; // optional public AttributeSetId attributeSetId; // optional
@ -125,7 +125,7 @@ public final class AttributeElement extends ASN1Any {
if (attributeSetId != null) { if (attributeSetId != null) {
numFields++; numFields++;
} }
BEREncoding fields[] = new BEREncoding[numFields]; BEREncoding[] fields = new BEREncoding[numFields];
int x = 0; int x = 0;
if (attributeSetId != null) { if (attributeSetId != null) {
fields[x++] = attributeSetId.berEncode(BEREncoding.CONTEXT_SPECIFIC_TAG, 1); fields[x++] = attributeSetId.berEncode(BEREncoding.CONTEXT_SPECIFIC_TAG, 1);
@ -153,13 +153,15 @@ public final class AttributeElement extends ASN1Any {
} }
str.append("attributeType "); str.append("attributeType ");
str.append(attributeType); str.append(attributeType);
outputted++; str.append(", ");
if (0 < outputted) {
str.append(", ");
}
str.append("attributeValue "); str.append("attributeValue ");
str.append(attributeValue); str.append(attributeValue);
str.append("}"); str.append("}");
return str.toString(); return str.toString();
} }
@Override
public int compareTo(AttributeElement o) {
return attributeType.toString().compareTo(o.attributeType.toString());
}
} }

View file

@ -2,7 +2,11 @@ package org.xbib.z3950.common.cql;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.asn1.ASN1Integer;
import org.xbib.cql.CQLParser; import org.xbib.cql.CQLParser;
import org.xbib.z3950.common.v3.AttributeElement;
import org.xbib.z3950.common.v3.AttributeElementAttributeValue;
import java.util.Collections;
class CQL2RPNTest { class CQL2RPNTest {
@ -14,7 +18,7 @@ class CQL2RPNTest {
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();
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); assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 2, attributeValue {numeric 3}}{attributeType 4, attributeValue {numeric 2}}{attributeType 5, attributeValue {numeric 100}}{attributeType 1, attributeValue {numeric 4}}}, term {general \"Test\"}}}}}", q);
} }
@Test @Test
@ -25,6 +29,19 @@ class CQL2RPNTest {
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();
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); assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 2, attributeValue {numeric 3}}{attributeType 4, attributeValue {numeric 1}}{attributeType 5, attributeValue {numeric 100}}{attributeType 1, attributeValue {numeric 4}}}, term {general \"a phrase\"}}}}}", q);
}
@Test
void testWithAttribute() {
AttributeElement ae = new AttributeElement();
ae.attributeType = new ASN1Integer(2);
String cql = "dc.title = \"a phrase\"";
CQLParser parser = new CQLParser(cql);
parser.parse();
CQLRPNGenerator generator = new CQLRPNGenerator(Collections.singleton(ae));
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 4, attributeValue {numeric 1}}{attributeType 5, attributeValue {numeric 100}}{attributeType 1, attributeValue {numeric 4}}}, term {general \"a phrase\"}}}}}", q);
} }
} }