new client api subproject
This commit is contained in:
parent
39a962cbdf
commit
9ae052559b
20 changed files with 279 additions and 145 deletions
|
@ -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'
|
||||||
|
|
3
z3950-client-api/build.gradle
Normal file
3
z3950-client-api/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
dependencies {
|
||||||
|
api project(':z3950-common')
|
||||||
|
}
|
4
z3950-client-api/src/main/java/module-info.java
Normal file
4
z3950-client-api/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
module org.xbib.z3950lib.client.api {
|
||||||
|
exports org.xbib.z3950.client.api;
|
||||||
|
requires transitive org.xbib.z3950lib.common;
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package org.xbib.z3950.api;
|
package org.xbib.z3950.client.api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client provider.
|
* Client provider.
|
|
@ -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')}"
|
||||||
}
|
}
|
5
z3950-client-jdk/src/main/java/module-info.java
Normal file
5
z3950-client-jdk/src/main/java/module-info.java
Normal 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;
|
||||||
|
}
|
|
@ -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,
|
|
@ -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"));
|
||||||
}
|
}
|
|
@ -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"));
|
||||||
}
|
}
|
|
@ -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))
|
|
@ -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')}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
module org.xbib.z3950lib.client {
|
|
||||||
exports org.xbib.z3950.client;
|
|
||||||
requires transitive org.xbib.z3950lib.common;
|
|
||||||
requires java.logging;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue