From e2c4c0d607295068ed7413e781e58d88c8a9beb8 Mon Sep 17 00:00:00 2001 From: Pascal Christoph Date: Fri, 19 Apr 2024 11:55:40 +0200 Subject: [PATCH 1/2] Encode "leader" also if it's passed as one literal (#454) "leader" can be given aa top-level literal or as literal in an entity. This makes the claim "The stream expected by the encoder is compatible to the streams emitted by the {@link Marc21Decoder} and the {@link MarcXmlHandler}." true again. --- .../biblio/iso2709/Iso2709Constants.java | 15 ++++----- .../biblio/marc21/Marc21Encoder.java | 32 +++++++++++++++++-- .../biblio/marc21/Marc21EncoderTest.java | 22 +++++++++++++ 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/metafacture-biblio/src/main/java/org/metafacture/biblio/iso2709/Iso2709Constants.java b/metafacture-biblio/src/main/java/org/metafacture/biblio/iso2709/Iso2709Constants.java index ebe9475c..02a7ec3f 100644 --- a/metafacture-biblio/src/main/java/org/metafacture/biblio/iso2709/Iso2709Constants.java +++ b/metafacture-biblio/src/main/java/org/metafacture/biblio/iso2709/Iso2709Constants.java @@ -23,9 +23,13 @@ * @author Christoph Böhme * */ -final class Iso2709Constants { +public final class Iso2709Constants { - static final int RECORD_LABEL_LENGTH = 24; + public static final int IMPL_CODES_START = 6; + public static final int IMPL_CODES_LENGTH = 4; + public static final int RECORD_LABEL_LENGTH = 24; + public static final int RECORD_STATUS_POS = 5; + public static final int SYSTEM_CHARS_START = 17; static final int MIN_RECORD_LENGTH = RECORD_LABEL_LENGTH + 2; static final int MAX_RECORD_LENGTH = 99_999; @@ -38,18 +42,11 @@ final class Iso2709Constants { static final int RECORD_LENGTH_START = 0; static final int RECORD_LENGTH_LENGTH = 5; - static final int RECORD_STATUS_POS = 5; - - static final int IMPL_CODES_START = 6; - static final int IMPL_CODES_LENGTH = 4; - static final int INDICATOR_LENGTH_POS = 10; static final int IDENTIFIER_LENGTH_POS = 11; static final int BASE_ADDRESS_START = 12; static final int BASE_ADDRESS_LENGTH = 5; - - static final int SYSTEM_CHARS_START = 17; static final int SYSTEM_CHARS_LENGTH = 3; static final int FIELD_LENGTH_LENGTH_POS = 20; diff --git a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java index 876f8520..6be0a0d0 100644 --- a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java +++ b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java @@ -16,6 +16,7 @@ package org.metafacture.biblio.marc21; +import org.metafacture.biblio.iso2709.Iso2709Constants; import org.metafacture.biblio.iso2709.RecordBuilder; import org.metafacture.biblio.iso2709.RecordFormat; import org.metafacture.framework.FluxCommand; @@ -180,7 +181,12 @@ public void literal(final String name, final String value) { builder.appendSubfield(name.toCharArray(), value); break; case IN_LEADER_ENTITY: - processLiteralInLeader(name, value); + if (name == Marc21EventNames.LEADER_ENTITY) { + processLeaderAsOneLiteral(value); + } + else { + processLeaderAsSubfields(name, value); + } break; case IN_RECORD: processTopLevelLiteral(name, value); @@ -190,7 +196,22 @@ public void literal(final String name, final String value) { } } - private void processLiteralInLeader(final String name, final String value) { + private void processLeaderAsOneLiteral(final String value) { + if (value.length() != Iso2709Constants.RECORD_LABEL_LENGTH) { + throw new FormatException( + "leader literal must contain " + Iso2709Constants.RECORD_LABEL_LENGTH + " characters:" + value); + } + processLeaderAsSubfields(Marc21EventNames.RECORD_STATUS_LITERAL, String.valueOf(value.charAt(Iso2709Constants.RECORD_STATUS_POS))); + processLeaderAsSubfields(Marc21EventNames.RECORD_TYPE_LITERAL, String.valueOf(value.charAt(Iso2709Constants.IMPL_CODES_START))); + processLeaderAsSubfields(Marc21EventNames.BIBLIOGRAPHIC_LEVEL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.IMPL_CODES_START + 1))); + processLeaderAsSubfields(Marc21EventNames.TYPE_OF_CONTROL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.IMPL_CODES_START + 2))); + processLeaderAsSubfields(Marc21EventNames.CHARACTER_CODING_LITERAL, String.valueOf(value.charAt(Iso2709Constants.RECORD_STATUS_POS + Iso2709Constants.IMPL_CODES_LENGTH))); + processLeaderAsSubfields(Marc21EventNames.ENCODING_LEVEL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.SYSTEM_CHARS_START))); + processLeaderAsSubfields(Marc21EventNames.CATALOGING_FORM_LITERAL, String.valueOf(value.charAt(Iso2709Constants.SYSTEM_CHARS_START + 1))); + processLeaderAsSubfields(Marc21EventNames.MULTIPART_LEVEL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.SYSTEM_CHARS_START + 2))); + } + + private void processLeaderAsSubfields(final String name, final String value) { if (value.length() != 1) { throw new FormatException( "literal must only contain a single character:" + name); @@ -251,7 +272,12 @@ private void processTopLevelLiteral(final String name, final String value) { // these literals here. return; } - builder.appendReferenceField(name.toCharArray(), value); + if (Marc21EventNames.LEADER_ENTITY.equals(name)) { + processLeaderAsOneLiteral(value); + } + else { + builder.appendReferenceField(name.toCharArray(), value); + } } @Override diff --git a/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java b/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java index 41e8d2b6..b766104a 100644 --- a/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java +++ b/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java @@ -114,4 +114,26 @@ public void issue278ShouldNotFailWhenProcessingLeaderEntity() { verify(receiver).process(any(String.class)); } + @Test + public void issue454ShouldNotFailWhenProcessingEntityLeaderAsOneString() { + marc21Encoder.startRecord(""); + marc21Encoder.startEntity(LEADER_ENTITY); + marc21Encoder.literal(LEADER_ENTITY, "02602pam a2200529 c 4500"); + marc21Encoder.endEntity(); + marc21Encoder.endEntity(); + marc21Encoder.endRecord(); + + verify(receiver).process(matches("00026pam a2200025 c 4500\u001e\u001d")); + } + + @Test + public void issue454ShouldNotFailWhenProcessingLeaderAsOneString() { + marc21Encoder.startRecord(""); + marc21Encoder.literal(LEADER_ENTITY, "02602pam a2200529 c 4500"); + marc21Encoder.endEntity(); + marc21Encoder.endRecord(); + + verify(receiver).process(matches("00026pam a2200025 c 4500\u001e\u001d")); + } + } From eb38a1bd29cb7a306561248da428dd60f3c2eaae Mon Sep 17 00:00:00 2001 From: Pascal Christoph Date: Mon, 22 Apr 2024 11:55:29 +0200 Subject: [PATCH 2/2] Add test for #524 (#454) - fix typo - remove superflous endEntity - add method to avoid unnecessary char-string conversion --- .../biblio/marc21/Marc21Encoder.java | 23 +++++++++++-------- .../biblio/marc21/Marc21EncoderTest.java | 15 ++++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java index 6be0a0d0..3cd536fe 100644 --- a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java +++ b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/Marc21Encoder.java @@ -199,16 +199,16 @@ public void literal(final String name, final String value) { private void processLeaderAsOneLiteral(final String value) { if (value.length() != Iso2709Constants.RECORD_LABEL_LENGTH) { throw new FormatException( - "leader literal must contain " + Iso2709Constants.RECORD_LABEL_LENGTH + " characters:" + value); + "leader literal must contain " + Iso2709Constants.RECORD_LABEL_LENGTH + " characters: " + value); } - processLeaderAsSubfields(Marc21EventNames.RECORD_STATUS_LITERAL, String.valueOf(value.charAt(Iso2709Constants.RECORD_STATUS_POS))); - processLeaderAsSubfields(Marc21EventNames.RECORD_TYPE_LITERAL, String.valueOf(value.charAt(Iso2709Constants.IMPL_CODES_START))); - processLeaderAsSubfields(Marc21EventNames.BIBLIOGRAPHIC_LEVEL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.IMPL_CODES_START + 1))); - processLeaderAsSubfields(Marc21EventNames.TYPE_OF_CONTROL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.IMPL_CODES_START + 2))); - processLeaderAsSubfields(Marc21EventNames.CHARACTER_CODING_LITERAL, String.valueOf(value.charAt(Iso2709Constants.RECORD_STATUS_POS + Iso2709Constants.IMPL_CODES_LENGTH))); - processLeaderAsSubfields(Marc21EventNames.ENCODING_LEVEL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.SYSTEM_CHARS_START))); - processLeaderAsSubfields(Marc21EventNames.CATALOGING_FORM_LITERAL, String.valueOf(value.charAt(Iso2709Constants.SYSTEM_CHARS_START + 1))); - processLeaderAsSubfields(Marc21EventNames.MULTIPART_LEVEL_LITERAL, String.valueOf(value.charAt(Iso2709Constants.SYSTEM_CHARS_START + 2))); + processLeaderAsSubfields(Marc21EventNames.RECORD_STATUS_LITERAL, value.charAt(Iso2709Constants.RECORD_STATUS_POS)); + processLeaderAsSubfields(Marc21EventNames.RECORD_TYPE_LITERAL, value.charAt(Iso2709Constants.IMPL_CODES_START)); + processLeaderAsSubfields(Marc21EventNames.BIBLIOGRAPHIC_LEVEL_LITERAL, value.charAt(Iso2709Constants.IMPL_CODES_START + 1)); + processLeaderAsSubfields(Marc21EventNames.TYPE_OF_CONTROL_LITERAL, value.charAt(Iso2709Constants.IMPL_CODES_START + 2)); + processLeaderAsSubfields(Marc21EventNames.CHARACTER_CODING_LITERAL, value.charAt(Iso2709Constants.RECORD_STATUS_POS + Iso2709Constants.IMPL_CODES_LENGTH)); + processLeaderAsSubfields(Marc21EventNames.ENCODING_LEVEL_LITERAL, value.charAt(Iso2709Constants.SYSTEM_CHARS_START)); + processLeaderAsSubfields(Marc21EventNames.CATALOGING_FORM_LITERAL, value.charAt(Iso2709Constants.SYSTEM_CHARS_START + 1)); + processLeaderAsSubfields(Marc21EventNames.MULTIPART_LEVEL_LITERAL, value.charAt(Iso2709Constants.SYSTEM_CHARS_START + 2)); } private void processLeaderAsSubfields(final String name, final String value) { @@ -216,7 +216,10 @@ private void processLeaderAsSubfields(final String name, final String value) { throw new FormatException( "literal must only contain a single character:" + name); } - final char code = value.charAt(0); + processLeaderAsSubfields(name, value.charAt(0)); + } + + private void processLeaderAsSubfields(final String name, final char code) { switch (name) { case Marc21EventNames.RECORD_STATUS_LITERAL: requireValidCode(code, Marc21Constants.RECORD_STATUS_CODES); diff --git a/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java b/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java index b766104a..e8e70325 100644 --- a/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java +++ b/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/Marc21EncoderTest.java @@ -120,7 +120,6 @@ public void issue454ShouldNotFailWhenProcessingEntityLeaderAsOneString() { marc21Encoder.startEntity(LEADER_ENTITY); marc21Encoder.literal(LEADER_ENTITY, "02602pam a2200529 c 4500"); marc21Encoder.endEntity(); - marc21Encoder.endEntity(); marc21Encoder.endRecord(); verify(receiver).process(matches("00026pam a2200025 c 4500\u001e\u001d")); @@ -130,10 +129,22 @@ public void issue454ShouldNotFailWhenProcessingEntityLeaderAsOneString() { public void issue454ShouldNotFailWhenProcessingLeaderAsOneString() { marc21Encoder.startRecord(""); marc21Encoder.literal(LEADER_ENTITY, "02602pam a2200529 c 4500"); - marc21Encoder.endEntity(); marc21Encoder.endRecord(); verify(receiver).process(matches("00026pam a2200025 c 4500\u001e\u001d")); } + @Test + public void issue524ShouldComputeValidLeader() { + marc21Encoder.startRecord(""); + marc21Encoder.literal(LEADER_ENTITY, "00000pam a7777777 c 4444"); + marc21Encoder.startEntity("021a "); + marc21Encoder.literal("v", "Fritz"); + marc21Encoder.literal("n", "Bauer"); + marc21Encoder.endEntity(); + marc21Encoder.endRecord(); + + verify(receiver).process(matches("00055pam a2200037 c 4500021001700000\u001e.*\u001d")); + } + }