diff --git a/gradle.properties b/gradle.properties index 7235de7..b0095b2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group = org.xbib name = z3950 -version = 5.0.3 +version = 5.0.4 org.gradle.warning.mode = ALL diff --git a/z3950-asn1/src/main/java/org/xbib/asn1/ASN1Any.java b/z3950-asn1/src/main/java/org/xbib/asn1/ASN1Any.java index cde54b3..92b0946 100644 --- a/z3950-asn1/src/main/java/org/xbib/asn1/ASN1Any.java +++ b/z3950-asn1/src/main/java/org/xbib/asn1/ASN1Any.java @@ -45,8 +45,7 @@ public class ASN1Any { * @throws ASN1Exception If the BER encoding is incorrect. * Never occurs for ASN1Any. */ - public void berDecode(BEREncoding berEncoding, boolean checkTag) - throws ASN1Exception { + public void berDecode(BEREncoding berEncoding, boolean checkTag) throws ASN1Exception { asn1anyBer = berEncoding; } diff --git a/z3950-asn1/src/main/java/org/xbib/asn1/ASN1OctetString.java b/z3950-asn1/src/main/java/org/xbib/asn1/ASN1OctetString.java index f5bcb61..141f3e3 100644 --- a/z3950-asn1/src/main/java/org/xbib/asn1/ASN1OctetString.java +++ b/z3950-asn1/src/main/java/org/xbib/asn1/ASN1OctetString.java @@ -1,5 +1,6 @@ package org.xbib.asn1; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /** @@ -27,6 +28,8 @@ public class ASN1OctetString extends ASN1Any { private byte[] octets; + private final Charset charset; + /** * Constructor for an OCTET STRING object. The tag is set to the * default of UNIVERSAL 4, and its value to the given bytes. @@ -34,6 +37,7 @@ public class ASN1OctetString extends ASN1Any { */ public ASN1OctetString(byte[] data) { octets = new byte[data.length]; + this.charset = StandardCharsets.ISO_8859_1; System.arraycopy(data, 0, octets, 0, data.length); } @@ -44,7 +48,12 @@ public class ASN1OctetString extends ASN1Any { * @param str string */ public ASN1OctetString(String str) { - octets = str.getBytes(StandardCharsets.ISO_8859_1); + this(str, StandardCharsets.ISO_8859_1); + } + + public ASN1OctetString(String str, Charset charset) { + this.octets = str.getBytes(charset); + this.charset = charset; } /** @@ -55,7 +64,8 @@ public class ASN1OctetString extends ASN1Any { * @throws ASN1Exception If the BER encoding is incorrect. */ public ASN1OctetString(BEREncoding ber, boolean checkTag) throws ASN1Exception { - super(ber, checkTag); + this.charset = StandardCharsets.ISO_8859_1; + berDecode(ber, checkTag); } /** @@ -80,7 +90,7 @@ public class ASN1OctetString extends ASN1Any { for (int anEncoding : encoding) { buf.append((char) (anEncoding & 0x00ff)); } - octets = buf.toString().getBytes(StandardCharsets.ISO_8859_1); + octets = buf.toString().getBytes(charset); } else { throw new ASN1EncodingException("decode from constructed NOT IMPLEMENTED YET"); } @@ -140,7 +150,7 @@ public class ASN1OctetString extends ASN1Any { * @return the object. */ public ASN1OctetString set(String str) { - octets = str.getBytes(StandardCharsets.ISO_8859_1); + octets = str.getBytes(charset); return this; } @@ -150,7 +160,7 @@ public class ASN1OctetString extends ASN1Any { * @return the OCTET STRING's current value. */ public String get() { - return new String(octets, StandardCharsets.ISO_8859_1); + return new String(octets, charset); } /** diff --git a/z3950-client-jdk/src/main/java/org/xbib/z3950/client/jdk/JDKZClient.java b/z3950-client-jdk/src/main/java/org/xbib/z3950/client/jdk/JDKZClient.java index 0dcd022..e8d013a 100644 --- a/z3950-client-jdk/src/main/java/org/xbib/z3950/client/jdk/JDKZClient.java +++ b/z3950-client-jdk/src/main/java/org/xbib/z3950/client/jdk/JDKZClient.java @@ -1,5 +1,6 @@ package org.xbib.z3950.client.jdk; +import java.nio.charset.StandardCharsets; import org.xbib.asn1.io.InputStreamBERReader; import org.xbib.asn1.io.OutputStreamBERWriter; import org.xbib.z3950.api.TimeoutListener; @@ -164,7 +165,7 @@ public class JDKZClient implements Client, Closeable { try { lock.lock(); SearchOperation search = new SearchOperation(berReader, berWriter, resultSetName, databases, host); - search.executePQF(query); + search.executePQF(query, StandardCharsets.UTF_8); if (!search.isSuccess()) { logger.log(Level.WARNING, MessageFormat.format("search was not a success [{0}]", query)); } else { diff --git a/z3950-client-jdk/src/test/java/org/xbib/z3950/client/jdk/test/LVIZClientTest.java b/z3950-client-jdk/src/test/java/org/xbib/z3950/client/jdk/test/LVIZClientTest.java index 64e5d98..8385dda 100644 --- a/z3950-client-jdk/src/test/java/org/xbib/z3950/client/jdk/test/LVIZClientTest.java +++ b/z3950-client-jdk/src/test/java/org/xbib/z3950/client/jdk/test/LVIZClientTest.java @@ -14,7 +14,7 @@ class LVIZClientTest { @Test void testLVI() { - String query = "@attr 1=4 linux"; + String query = "@attr 1=4 Köln"; int from = 1; int size = 10; try (JDKZClient client = newZClient()) { @@ -32,8 +32,8 @@ class LVIZClientTest { private JDKZClient newZClient() { JDKZClient.Builder builder = JDKZClient.builder(); - builder.setHost("sru.hbz-nrw.de"); - builder.setPort(210); + builder.setHost("localhost"); + builder.setPort(1210); builder.setDatabases(Collections.singletonList("LVI")); builder.setElementSetName(null); builder.setPreferredRecordSyntax("xml"); diff --git a/z3950-common/src/main/java/org/xbib/z3950/common/operations/AbstractOperation.java b/z3950-common/src/main/java/org/xbib/z3950/common/operations/AbstractOperation.java index 2374d3c..c3e621f 100644 --- a/z3950-common/src/main/java/org/xbib/z3950/common/operations/AbstractOperation.java +++ b/z3950-common/src/main/java/org/xbib/z3950/common/operations/AbstractOperation.java @@ -1,5 +1,7 @@ package org.xbib.z3950.common.operations; +import java.util.logging.Level; +import java.util.logging.Logger; import org.xbib.asn1.ASN1Any; import org.xbib.asn1.ASN1Exception; import org.xbib.asn1.BEREncoding; @@ -53,6 +55,8 @@ import java.io.IOException; */ public class AbstractOperation { + private static final Logger logger = Logger.getLogger(AbstractOperation.class.getName()); + protected final BERReader reader; protected final BERWriter writer; @@ -122,18 +126,24 @@ public class AbstractOperation { } try { switch (ber.getTag()) { - case 20: + case 20 -> { return (IN) new InitializeRequest(ber, false); - case 21: + } + case 21 -> { return (IN) new InitializeResponse(ber, false); - case 22: + } + case 22 -> { return (IN) new SearchRequest(ber, false); - case 23: + } + case 23 -> { return (IN) new SearchResponse(ber, false); - case 24: + } + case 24 -> { return (IN) new PresentRequest(ber, false); - case 25: + } + case 25 -> { return (IN) new PresentResponse(ber, false); + } // 26 new DeleteResultSetRequest(ber, false); // 27 new DeleteResultSetResponse(ber, false); // 28 new AccessControlRequest(ber, false); @@ -143,23 +153,29 @@ public class AbstractOperation { // 32 new TriggerResourceControlRequest(ber, false); // 33 new ResourceReportRequest(ber, false); // 34 new ResourceReportResponse(ber, false); - case 35: + case 35 -> { return (IN) new ScanRequest(ber, false); - case 36: + } + case 36 -> { return (IN) new ScanResponse(ber, false); + } // 43 new SortRequest(ber, false); // 44 new SortResponse(ber, false); // 45 new Segment(ber, false); // 46 new ExtendedServicesRequest(ber, false); // 47 new ExtendedServicesResponse(ber, false); - case 48: + case 48 -> { return (IN) new Close(ber, false); + } + default -> { + throw new ASN1Exception("bad BER encoding: " + ber.getTag() + " not matched"); + } } } catch (Exception e) { // class cast exception if Close is returned, ignore + logger.log(Level.SEVERE, e.getMessage(), e); return null; } - throw new ASN1Exception("bad BER encoding: choice not matched"); } } diff --git a/z3950-common/src/main/java/org/xbib/z3950/common/operations/InitOperation.java b/z3950-common/src/main/java/org/xbib/z3950/common/operations/InitOperation.java index 08a7bac..2b295cc 100644 --- a/z3950-common/src/main/java/org/xbib/z3950/common/operations/InitOperation.java +++ b/z3950-common/src/main/java/org/xbib/z3950/common/operations/InitOperation.java @@ -86,38 +86,40 @@ public class InitOperation extends AbstractOperation 0) { - targetInfo += " (Version " + targetVersion + ")"; + if (initResp.protocolVersion != null) { + for (int n = 0; n < initResp.protocolVersion.value.get().length; n++) { + if (initResp.protocolVersion.value.get()[n]) { + targetVersion = n + 1; + } + } + if (targetVersion > 0) { + targetInfo += " (Version " + targetVersion + ")"; + } + } else { + targetInfo += " (Version unknown)"; } - } else { - targetInfo += " (Version unknown)"; + if (initResp.userInformationField != null && initResp.userInformationField.getSingleASN1Type() != null) { + targetInfo += "\n" + initResp.userInformationField.getSingleASN1Type().toString(); + } + if (initResp.otherInfo != null) { + targetInfo += "\n" + initResp.otherInfo.toString(); + } + targetInfo = targetInfo.replaceAll("\"", ""); } - if (initResp.userInformationField != null && initResp.userInformationField.getSingleASN1Type() != null) { - targetInfo += "\n" + initResp.userInformationField.getSingleASN1Type().toString(); - } - if (initResp.otherInfo != null) { - targetInfo += "\n" + initResp.otherInfo.toString(); - } - targetInfo = targetInfo.replaceAll("\"", ""); if (initListener != null) { initListener.onInit(targetVersion, targetInfo); } - return !initResp.result.get(); + return initResp != null && !initResp.result.get(); } public String getTargetInfo() { diff --git a/z3950-common/src/main/java/org/xbib/z3950/common/operations/SearchOperation.java b/z3950-common/src/main/java/org/xbib/z3950/common/operations/SearchOperation.java index da4c152..e5da927 100644 --- a/z3950-common/src/main/java/org/xbib/z3950/common/operations/SearchOperation.java +++ b/z3950-common/src/main/java/org/xbib/z3950/common/operations/SearchOperation.java @@ -1,5 +1,6 @@ package org.xbib.z3950.common.operations; +import java.nio.charset.Charset; import org.xbib.asn1.ASN1Boolean; import org.xbib.asn1.ASN1GeneralString; import org.xbib.asn1.ASN1Integer; @@ -53,8 +54,8 @@ public class SearchOperation extends AbstractOperation result; private RPNQuery rpnQuery; public PQFRPNGenerator() { + this(StandardCharsets.ISO_8859_1); + } + + public PQFRPNGenerator(Charset charset) { this.result = new Stack<>(); + this.charset = charset; } public RPNQuery getResult() { @@ -46,9 +55,6 @@ public class PQFRPNGenerator implements Visitor { ASN1Any any = result.pop(); if (any instanceof RPNStructure) { rpnQuery.rpn = (RPNStructure) any; - } else if (any instanceof ASN1OctetString) { - // TODO - logger.log(Level.INFO, "found ASN1OctetString = " + ((ASN1OctetString) any).get()); } if (pqf.getAttrSet() == null) { // Z39.50 BIB-1: urn:oid:1.2.840.10003.3.1 @@ -131,7 +137,7 @@ public class PQFRPNGenerator implements Visitor { @Override public void visit(Term term) { - result.push(new ASN1OctetString(term.getValue())); + result.push(new ASN1OctetString(term.getValue(), charset)); } @Override diff --git a/z3950-common/src/main/java/org/xbib/z3950/common/pqf/Term.java b/z3950-common/src/main/java/org/xbib/z3950/common/pqf/Term.java index e428619..87039c4 100644 --- a/z3950-common/src/main/java/org/xbib/z3950/common/pqf/Term.java +++ b/z3950-common/src/main/java/org/xbib/z3950/common/pqf/Term.java @@ -2,9 +2,6 @@ package org.xbib.z3950.common.pqf; import java.math.BigDecimal; -/** - * - */ public class Term extends Node { private final String value; diff --git a/z3950-common/src/test/java/org/xbib/z3950/common/pqf/PQFTest.java b/z3950-common/src/test/java/org/xbib/z3950/common/pqf/PQFTest.java index 2ff16e6..2fd6627 100644 --- a/z3950-common/src/test/java/org/xbib/z3950/common/pqf/PQFTest.java +++ b/z3950-common/src/test/java/org/xbib/z3950/common/pqf/PQFTest.java @@ -1,5 +1,6 @@ package org.xbib.z3950.common.pqf; +import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Test; import org.xbib.z3950.common.v3.RPNQuery; @@ -38,8 +39,16 @@ class PQFTest { createRPNQueryFromPQF(q).toString()); } + @Test + void testRPN4() { + // test UTF-8 + String q = "@attr 1=3 Jörg"; + assertEquals("{attributeSetId 1.2.840.10003.3.1, rpn {op {attrTerm {attributes {{attributeType 1, attributeValue {numeric 3}}}, term {general \"J\\703\\666rg\"}}}}}", + createRPNQueryFromPQF(q).toString()); + } + private RPNQuery createRPNQueryFromPQF(String query) { - PQFRPNGenerator generator = new PQFRPNGenerator(); + PQFRPNGenerator generator = new PQFRPNGenerator(StandardCharsets.UTF_8); org.xbib.z3950.common.pqf.PQFParser parser = new org.xbib.z3950.common.pqf.PQFParser(new StringReader(query)); parser.parse(); parser.getResult().accept(generator);