Skip to content

Commit

Permalink
MODLD-385: Create beans for Default and StructureB LCCN normalization
Browse files Browse the repository at this point in the history
  • Loading branch information
pkjacob committed Jun 3, 2024
1 parent de918ad commit bff3055
Show file tree
Hide file tree
Showing 24 changed files with 183 additions and 142 deletions.
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
* Clean up API documentation to enable checking of the request/response bodies samples([MSEARCH-546](https://issues.folio.org/browse/MSEARCH-546))

### Dependencies
* Bump `spring-boot` from `3.2.3` to `3.3.0`
* Bump `spring-boot` from `3.1.5` to `3.2.3`
* Bump `folio-spring-support` from `7.2.0` to `8.1.0`
* Bump `folio-service-tools` from `3.1.0` to `4.0.0`
* Bump `folio-cql2pgjson` from `35.1.0` to `35.2.0`
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ and [Cross-cluster replication](https://docs.aws.amazon.com/opensearch-service/l
| KAFKA_CONTRIBUTORS_TOPIC_REPLICATION_FACTOR | - | Replication factor for `search.instance-contributor` topic. |
| KAFKA_CONSORTIUM_INSTANCE_CONCURRENCY | 2 | Custom number of kafka concurrent threads for consortium.instance message consuming. |
| KAFKA_LOCATION_CONCURRENCY | 1 | Custom number of kafka concurrent threads for inventory.location message consuming. |
| KAFKA_BIBFRAME_CONCURRENCY | 1 | Custom number of kafka concurrent threads for bibframe message consuming. |
| KAFKA_CONSORTIUM_INSTANCE_TOPIC_PARTITIONS | 50 | Amount of partitions for `search.consortium.instance` topic. |
| KAFKA_CONSORTIUM_INSTANCE_TOPIC_REPLICATION_FACTOR | - | Replication factor for `search.consortium.instance` topic. |
| KAFKA_SUBJECTS_CONCURRENCY | 2 | Custom number of kafka concurrent threads for subject message consuming. |
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package org.folio.search.cql;

import lombok.RequiredArgsConstructor;
import org.folio.search.utils.SearchUtils;
import org.folio.search.service.lccn.LccnNormalizer;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class LccnSearchTermProcessor implements SearchTermProcessor {

private final LccnNormalizer lccnNormalizer;

@Override
public String getSearchTerm(String inputTerm) {
return SearchUtils.normalizeLccn(inputTerm);
return lccnNormalizer.apply(inputTerm)
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,7 @@ public void handleBibframeEvents(List<ConsumerRecord<String, ResourceEvent>> con
.map(bibframe -> bibframe.resourceName(BIBFRAME_RESOURCE).id(getResourceEventId(bibframe)))
.toList();

folioMessageBatchProcessor.consumeBatchWithFallback(batch, KAFKA_RETRY_TEMPLATE_NAME,
resourceService::indexResources, KafkaMessageListener::logFailedEvent);
indexResources(batch, resourceService::indexResources);
}

private void indexResources(List<ResourceEvent> batch, Consumer<List<ResourceEvent>> indexConsumer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.folio.search.service.lccn;

import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service
@Primary
public class DefaultLccnNormalizer implements LccnNormalizer {

@Override
public Optional<String> apply(String lccn) {
if (StringUtils.isBlank(lccn)) {
return Optional.empty();
}

return Optional.of(StringUtils.deleteWhitespace(lccn))
.map(String::toLowerCase);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.folio.search.service.lccn;

import java.util.Optional;
import java.util.function.Function;

public interface LccnNormalizer extends Function<String, Optional<String>> {
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package org.folio.search.service.setter.bibframe;
package org.folio.search.service.lccn;

import jakarta.validation.constraints.NotNull;
import java.util.Optional;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

/**
* Class responsible for normalizing Structure B LCCN values.
*/
@Log4j2
@Service
public class LccnNormalizer {
public class LccnNormalizerStructureB implements LccnNormalizer {
private static final String NORMALIZED_LCCN_REGEX = "\\d{10}";
private static final char HYPHEN = '-';

Expand All @@ -19,7 +22,7 @@ public class LccnNormalizer {
* @param lccn LCCN to be normalized
* @return Returns the normalized LCCN. If the given LCCN is invalid, returns an empty Optional
*/
public Optional<String> normalizeLccn(@NotNull final String lccn) {
public Optional<String> apply(@NotNull final String lccn) {
var normalizedLccn = lccn;

// Remove white spaces
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.folio.search.domain.dto.Identifier;
import org.folio.search.integration.ReferenceDataService;
import org.folio.search.utils.SearchUtils;
import org.folio.search.service.lccn.LccnNormalizer;

public abstract class AbstractLccnProcessor<T> extends AbstractIdentifierProcessor<T> {

private static final List<String> LCCN_IDENTIFIER_NAME = List.of("LCCN", "Canceled LCCN");
private final LccnNormalizer lccnNormalizer;

protected AbstractLccnProcessor(ReferenceDataService referenceDataService) {
protected AbstractLccnProcessor(ReferenceDataService referenceDataService, LccnNormalizer lccnNormalizer) {
super(referenceDataService, LCCN_IDENTIFIER_NAME);
this.lccnNormalizer = lccnNormalizer;
}

@Override
public Set<String> getFieldValue(T entity) {
return filterIdentifiersValue(getIdentifiers(entity)).stream()
.map(SearchUtils::normalizeLccn)
.map(lccnNormalizer)
.flatMap(Optional::stream)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.folio.search.domain.dto.Authority;
import org.folio.search.domain.dto.Identifier;
import org.folio.search.integration.ReferenceDataService;
import org.folio.search.service.lccn.LccnNormalizer;
import org.folio.search.service.setter.AbstractLccnProcessor;
import org.springframework.stereotype.Component;

Expand All @@ -16,9 +17,10 @@ public class LccnAuthorityProcessor extends AbstractLccnProcessor<Authority> {
* Used by dependency injection.
*
* @param referenceDataService {@link ReferenceDataService} bean
* @param lccnNormalizer {@link LccnNormalizer} bean
*/
public LccnAuthorityProcessor(ReferenceDataService referenceDataService) {
super(referenceDataService);
public LccnAuthorityProcessor(ReferenceDataService referenceDataService, LccnNormalizer lccnNormalizer) {
super(referenceDataService, lccnNormalizer);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
Expand All @@ -32,13 +31,8 @@ public Set<String> getFieldValue(Bibframe bibframe) {
.filter(i -> ISBN.equals(i.getType()))
.map(BibframeInstancesInnerIdentifiersInner::getValue)
.filter(Objects::nonNull)
.map(this::normalizeIsbn)
.map(isbnProcessor::normalizeIsbn)
.flatMap(Collection::stream)
.collect(toCollection(LinkedHashSet::new));
}

public List<String> normalizeIsbn(String value) {
return isbnProcessor.normalizeIsbn(value);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
import lombok.RequiredArgsConstructor;
import org.folio.search.domain.dto.Bibframe;
import org.folio.search.domain.dto.BibframeInstancesInnerIdentifiersInner;
import org.folio.search.service.lccn.LccnNormalizer;
import org.folio.search.service.setter.FieldProcessor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class BibframeLccnProcessor implements FieldProcessor<Bibframe, Set<String>> {

@Qualifier("lccnNormalizerStructureB")
private final LccnNormalizer lccnNormalizer;

@Override
Expand All @@ -31,7 +34,7 @@ public Set<String> getFieldValue(Bibframe bibframe) {
.filter(i -> LCCN.equals(i.getType()))
.map(BibframeInstancesInnerIdentifiersInner::getValue)
.filter(Objects::nonNull)
.map(lccnNormalizer::normalizeLccn)
.map(lccnNormalizer)
.flatMap(Optional::stream)
.collect(toCollection(LinkedHashSet::new));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.folio.search.domain.dto.Identifier;
import org.folio.search.domain.dto.Instance;
import org.folio.search.integration.ReferenceDataService;
import org.folio.search.service.lccn.LccnNormalizer;
import org.folio.search.service.setter.AbstractLccnProcessor;
import org.springframework.stereotype.Component;

Expand All @@ -19,9 +20,10 @@ public class LccnInstanceProcessor extends AbstractLccnProcessor<Instance> {
* Used by dependency injection.
*
* @param referenceDataService {@link ReferenceDataService} bean
* @param lccnNormalizer {@link LccnNormalizer} bean
*/
public LccnInstanceProcessor(ReferenceDataService referenceDataService) {
super(referenceDataService);
public LccnInstanceProcessor(ReferenceDataService referenceDataService, LccnNormalizer lccnNormalizer) {
super(referenceDataService, lccnNormalizer);
}

@Override
Expand Down
14 changes: 0 additions & 14 deletions src/main/java/org/folio/search/utils/SearchUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -329,20 +329,6 @@ public static int getNumberOfRequests(Map<String, List<SearchDocumentBody>> requ
.sum();
}

/**
* Normalizes LCCN value.
*
* @param value LCCN value
* @return normalized LCCN value
*/
public static String normalizeLccn(String value) {
if (StringUtils.isBlank(value)) {
return null;
}

return StringUtils.deleteWhitespace(value).toLowerCase();
}

/**
* This method normalize the given string to an alphanumeric string.
* If the input string is null or blank, this method returns null.
Expand Down
3 changes: 0 additions & 3 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,6 @@ folio:
- name: search.consortium.instance
numPartitions: ${KAFKA_CONSORTIUM_INSTANCE_TOPIC_PARTITIONS:50}
replicationFactor: ${KAFKA_CONSORTIUM_INSTANCE_TOPIC_REPLICATION_FACTOR:}
- name: search.bibframe
numPartitions: ${KAFKA_BIBFRAME_TOPIC_PARTITIONS:3}
replicationFactor: ${KAFKA_BIBFRAME_TOPIC_REPLICATION_FACTOR:}
listener:
events:
concurrency: ${KAFKA_EVENTS_CONCURRENCY:2}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/model/bibframe.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"isbn": {
"type": "search",
"processor": "bibframeIsbnProcessor",
"searchTermProcessor": "bibframeIsbnSearchTermProcessor",
"searchTermProcessor": "isbnSearchTermProcessor",
"index": "standard",
"indexPlainValue": false
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
package org.folio.search.cql;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

import java.util.Optional;
import org.folio.search.service.lccn.LccnNormalizer;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;


@UnitTest
@ExtendWith(MockitoExtension.class)
class LccnSearchTermProcessorTest {
@Mock
private LccnNormalizer normalizer;
@InjectMocks
private LccnSearchTermProcessor lccnSearchTermProcessor;

@Test
void getSearchTerm_positive() {
// given
var searchTerm = " N 123456 ";
var lccnSearchTermProcessor = new LccnSearchTermProcessor();
var normalizedTerm = "n123456";
when(normalizer.apply(searchTerm)).thenReturn(Optional.of(normalizedTerm));

// when
var actual = lccnSearchTermProcessor.getSearchTerm(searchTerm);
assertThat(actual).isEqualTo("n123456");

// then
assertThat(actual).isEqualTo(normalizedTerm);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.folio.search.service.lccn;

import static org.assertj.core.api.Assertions.assertThat;

import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

@UnitTest
class DefaultLccnNormalizerTest {
private final DefaultLccnNormalizer lccnNormalizer = new DefaultLccnNormalizer();

@DisplayName("LCCN value normalization")
@CsvSource({"n 1234,n1234", " N 1234 ,n1234", "*1234,*1234", "1234*,1234*"})
@ParameterizedTest(name = "[{index}] value={0}, expected={1}")
void getLccnNormalized_parameterized(String value, String expected) {
var normalized = lccnNormalizer.apply(value);
assertThat(normalized).contains(expected);
}
}
Loading

0 comments on commit bff3055

Please sign in to comment.