update to OpenJDK 17, Gradle 7.5.1, add Groovy example

This commit is contained in:
Jörg Prante 2023-01-14 18:45:26 +01:00
parent 28a2ea875b
commit dcea5cc021
22 changed files with 334 additions and 82 deletions

View file

@ -4,7 +4,7 @@ plugins {
} }
wrapper { wrapper {
gradleVersion = "${project.property('gradle.wrapper.version')}" gradleVersion = libs.versions.gradle.get()
distributionType = Wrapper.DistributionType.ALL distributionType = Wrapper.DistributionType.ALL
} }
@ -24,11 +24,9 @@ ext {
} }
subprojects { subprojects {
apply plugin: 'java-library'
apply from: rootProject.file('gradle/ide/idea.gradle') apply from: rootProject.file('gradle/ide/idea.gradle')
apply from: rootProject.file('gradle/compile/java.gradle') apply from: rootProject.file('gradle/compile/java.gradle')
apply from: rootProject.file('gradle/test/junit5.gradle') apply from: rootProject.file('gradle/test/junit5.gradle')
apply from: rootProject.file('gradle/publishing/publication.gradle') apply from: rootProject.file('gradle/publishing/publication.gradle')
} }
apply from: rootProject.file('gradle/publishing/sonatype.gradle') apply from: rootProject.file('gradle/publishing/sonatype.gradle')

View file

@ -1,8 +1,5 @@
group = org.xbib group = org.xbib
name = z3950 name = z3950
version = 2.4.0 version = 5.0.0
gradle.wrapper.version = 7.3.2 org.gradle.warning.mode = ALL
netty.version = 4.1.74.Final
xbib-cql.version = 3.1.2
xbib-bibliographic-character-sets.version = 2.0.0

View file

@ -0,0 +1,30 @@
apply plugin: 'groovy'
dependencies {
implementation libs.groovy
}
compileGroovy {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
compileTestGroovy {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType(GroovyCompile) {
if (!options.compilerArgs.contains("-processor")) {
options.compilerArgs.add('-proc:none')
}
}
task groovydocJar(type: Jar, dependsOn: 'groovydoc') {
from groovydoc.destinationDir
archiveClassifier.set('groovydoc')
}
artifacts {
archives groovydocJar
}

View file

@ -0,0 +1,30 @@
apply plugin: 'groovy'
dependencies {
implementation libs.groovy
}
compileGroovy {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
compileTestGroovy {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType(GroovyCompile) {
options.compilerArgs
if (!options.compilerArgs.contains("-processor")) {
options.compilerArgs << '-proc:none'
}
}
task groovydocJar(type: Jar, dependsOn: 'groovydoc') {
from groovydoc.destinationDir
archiveClassifier.set('javadoc')
}
// BUG! exception in phase 'instruction selection' in source unit 'graphics/graphics-pdfbox-groovy/src/main/groovy/org/xbib/graphics/pdfbox/groovy/render/RowRenderer.groovy' unexpected NullPointerException
//compileGroovy.groovyOptions.configurationScript = rootProject.file('gradle/compile/groovyc.groovy')

View file

@ -0,0 +1,7 @@
import groovy.transform.TypeChecked
import groovy.transform.CompileStatic
withConfig(configuration) {
ast(TypeChecked)
ast(CompileStatic)
}

View file

@ -6,13 +6,13 @@ java {
} }
compileJava { compileJava {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_17
} }
compileTestJava { compileTestJava {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_17
} }
jar { jar {
@ -24,6 +24,7 @@ jar {
task sourcesJar(type: Jar, dependsOn: classes) { task sourcesJar(type: Jar, dependsOn: classes) {
classifier 'sources' classifier 'sources'
from sourceSets.main.allSource from sourceSets.main.allSource
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
} }
task javadocJar(type: Jar, dependsOn: javadoc) { task javadocJar(type: Jar, dependsOn: javadoc) {
@ -35,9 +36,11 @@ artifacts {
} }
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:all,-fallthrough' options.compilerArgs.add('-Xlint:all,-exports')
options.encoding = 'UTF-8'
} }
javadoc { tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet') options.addStringOption('Xdoclint:none', '-quiet')
options.encoding = 'UTF-8'
} }

View file

@ -1,12 +1,8 @@
def junitVersion = project.hasProperty('junit.version')?project.property('junit.version'):'5.6.2'
def hamcrestVersion = project.hasProperty('hamcrest.version')?project.property('hamcrest.version'):'2.2'
dependencies { dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}" testImplementation libs.junit.jupiter.api
testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" testImplementation libs.junit.jupiter.params
testImplementation "org.hamcrest:hamcrest-library:${hamcrestVersion}" testImplementation libs.hamcrest
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" testRuntimeOnly libs.junit.jupiter.engine
} }
test { test {
@ -24,6 +20,4 @@ test {
"${result.skippedTestCount} skipped" "${result.skippedTestCount} skipped"
} }
} }
// massive heap for for xmlunit DOM comparer
jvmArgs '-Xmx2048m'
} }

Binary file not shown.

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

6
gradlew vendored
View file

@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ org.gradle.wrapper.GradleWrapperMain \
"$@" "$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.

14
gradlew.bat vendored
View file

@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View file

@ -1,3 +1,34 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
version('gradle', '7.5.1')
version('groovy', '4.0.7')
version('junit', '5.9.2')
version('junit4', '4.13.2')
version('netty', '4.1.87.Final')
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')
library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit')
library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit')
library('junit-jupiter-vintage', 'org.junit.vintage', 'junit-vintage-engine').versionRef('junit4')
library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('2.2')
library('cql-common', 'org.xbib', 'cql-common').version('5.0.0')
library('netty-transport', 'io.netty', 'netty-transport').versionRef('netty')
library('netty-handler', 'io.netty', 'netty-handler').versionRef('netty')
library('netty-common', 'io.netty', 'netty-common').versionRef('netty')
library('netty-buffer', 'io.netty', 'netty-buffer').versionRef('netty')
library('charactersets', 'org.xbib', 'bibliographic-character-sets').version('2.0.0')
library('groovy', 'org.apache.groovy', 'groovy').versionRef('groovy')
library('groovy-xml', 'org.apache.groovy', 'groovy-xml').versionRef('groovy')
library('groovy-json', 'org.apache.groovy', 'groovy-json').versionRef('groovy')
library('groovy-nio', 'org.apache.groovy', 'groovy-nio').versionRef('groovy')
library('groovy-sql', 'org.apache.groovy', 'groovy-sql').versionRef('groovy')
library('groovy-macro', 'org.apache.groovy', 'groovy-macro').versionRef('groovy')
library('groovy-templates', 'org.apache.groovy', 'groovy-templates').versionRef('groovy')
library('groovy-test', 'org.apache.groovy', 'groovy-test').versionRef('groovy')
}
}
}
include 'z3950-asn1' include 'z3950-asn1'
include 'z3950-api' include 'z3950-api'
include 'z3950-common' include 'z3950-common'
@ -5,3 +36,4 @@ include 'z3950-client-api'
include 'z3950-client-jdk' include 'z3950-client-jdk'
include 'z3950-client-netty' include 'z3950-client-netty'
include 'z3950-sru' include 'z3950-sru'
include 'z3950-groovy'

View file

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

View file

@ -9,12 +9,9 @@ import java.util.Collections;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** class COPACTest {
*
*/
class SearchTest {
private static final Logger logger = Logger.getLogger(SearchTest.class.getName()); private static final Logger logger = Logger.getLogger(COPACTest.class.getName());
@Test @Test
void testCopac() throws Exception { void testCopac() throws Exception {
@ -35,7 +32,7 @@ class SearchTest {
.build(); .build();
client.searchPQF(query, from, length, client.searchPQF(query, from, length,
(status, total, returned, elapsedMillis) -> logger.log(Level.INFO, "total records = " + total), (status, total, returned, elapsedMillis) -> logger.log(Level.INFO, "total records = " + total),
record -> logger.log(Level.INFO, "found record " + record), record -> logger.log(Level.INFO, "found record " + record), // MODS
() -> logger.log(Level.WARNING, "timeout")); () -> logger.log(Level.WARNING, "timeout"));
client.close(); client.close();
} catch (NoRecordsReturnedException | MessageSizeTooSmallException e) { } catch (NoRecordsReturnedException | MessageSizeTooSmallException e) {

View file

@ -1,5 +1,6 @@
package org.xbib.z3950.client.jdk.test; package org.xbib.z3950.client.jdk.test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.z3950.client.jdk.JDKZClient; import org.xbib.z3950.client.jdk.JDKZClient;
@ -39,6 +40,7 @@ class GBVZClientTest {
} }
@Test @Test
@Disabled("unsupported search")
void testControlNumberZDB() { void testControlNumberZDB() {
String serviceName = "GBV"; String serviceName = "GBV";
String query = "bib.controlNumberZDB = 1413423-8"; String query = "bib.controlNumberZDB = 1413423-8";

View file

@ -0,0 +1,105 @@
package org.xbib.z3950.client.jdk.test;
import org.junit.jupiter.api.Test;
import org.xbib.z3950.client.jdk.JDKZClient;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
class LIBRISClientTest {
private static final Logger logger = Logger.getLogger(LIBRISClientTest.class.getName());
@Test
void testCQL() {
String serviceName = "LIBRIS";
String query = "bib.identifierISSN = 00280836";
int from = 1;
int size = 10;
try (JDKZClient client = newZClient(serviceName)) {
logger.log(Level.INFO, "executing CQL " + serviceName);
int count = client.searchCQL(query, from, size,
(status, total, returned, elapsedMillis) ->
logger.log(Level.INFO, serviceName + " total results = " + total),
record -> logger.log(Level.INFO, "record = " + record),
() -> logger.log(Level.INFO, "timeout"));
logger.log(Level.INFO, "returned records = " + count);
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
@Test
void testPQF() {
String serviceName = "LIBRIS";
String query = "@attr 1=8 \"00280836\"";
int from = 1;
int size = 10;
try (JDKZClient client = newZClient(serviceName)) {
logger.log(Level.INFO, "executing PQF " + serviceName);
int count = client.searchPQF(query, from, size,
(status, total, returned, elapsedMillis) ->
logger.log(Level.INFO, serviceName + " status = " + status + " total results = " + total),
record -> logger.log(Level.INFO, "record = " + record.toString(Charset.forName(client.getEncoding()))),
() -> logger.log(Level.WARNING, "timeout"));
logger.log(Level.INFO, "returned records = " + count);
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
private JDKZClient newZClient(String name) throws IOException {
return newZClient(getProperties(name));
}
private Properties getProperties(String name) throws IOException {
Properties properties = new Properties();
try (InputStream inputStream = getClass().getResourceAsStream(name + ".properties")) {
properties.load(inputStream);
}
return properties;
}
private static JDKZClient newZClient(Properties properties) {
JDKZClient.Builder builder = JDKZClient.builder();
if (properties.containsKey("host")) {
builder.setHost(properties.getProperty("host"));
}
if (properties.containsKey("port")) {
builder.setPort(Integer.parseInt(properties.getProperty("port")));
}
if (properties.containsKey("user")) {
builder.setUser(properties.getProperty("user"));
}
if (properties.containsKey("pass")) {
builder.setPass(properties.getProperty("pass"));
}
if (properties.containsKey("database")) {
builder.setDatabases(Collections.singletonList(properties.getProperty("database")));
}
if (properties.containsKey("elementsetname")) {
builder.setElementSetName(properties.getProperty("elementsetname"));
}
if (properties.containsKey("preferredrecordsyntax")) {
builder.setPreferredRecordSyntax(properties.getProperty("preferredrecordsyntax"));
}
if (properties.containsKey("resultsetname")) {
builder.setResultSetName(properties.getProperty("resultsetname"));
}
if (properties.containsKey("encoding")) {
builder.setEncoding(properties.getProperty("encoding"));
}
if (properties.containsKey("format")) {
builder.setFormat(properties.getProperty("format"));
}
if (properties.containsKey("type")) {
builder.setType(properties.getProperty("type"));
}
return builder.build();
}
}

View file

@ -1,8 +1,5 @@
package org.xbib.z3950.client.jdk.test; package org.xbib.z3950.client.jdk.test;
import org.junit.jupiter.api.Test;
import org.xbib.z3950.client.jdk.JDKZClient;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -11,51 +8,48 @@ import java.util.Collections;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.junit.jupiter.api.Test;
import org.xbib.z3950.client.jdk.JDKZClient;
/** class SWBClientTest {
*
*/
class DefaultClientTest {
private static final Logger logger = Logger.getLogger(DefaultClientTest.class.getName()); private static final Logger logger = Logger.getLogger(SWBClientTest.class.getName());
@Test @Test
void testCQL() { void testCQL() {
for (String serviceName : Arrays.asList("LIBRIS", "SWB")) { String serviceName = "SWB";
String query = "bib.identifierISSN = 00280836"; String query = "bib.identifierISSN = 00280836";
int from = 1; int from = 1;
int size = 10; int size = 10;
try (JDKZClient 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) ->
logger.log(Level.INFO, serviceName + " total results = " + total), logger.log(Level.INFO, serviceName + " total results = " + total),
record -> logger.log(Level.INFO, "record = " + record), record -> logger.log(Level.INFO, "record = " + record),
() -> logger.log(Level.INFO, "timeout")); () -> logger.log(Level.INFO, "timeout"));
logger.log(Level.INFO, "returned records = " + count); logger.log(Level.INFO, "returned records = " + count);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e); logger.log(Level.SEVERE, e.getMessage(), e);
}
} }
} }
@Test @Test
void testPQF() { void testPQF() {
for (String serviceName : Arrays.asList("LIBRIS", "SWB")) { String serviceName = "SWB";
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 (JDKZClient 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) ->
logger.log(Level.INFO, serviceName + " status = " + status + " total results = " + total), logger.log(Level.INFO, serviceName + " status = " + status + " total results = " + total),
record -> logger.log(Level.INFO, "record = " + record.toString(Charset.forName(client.getEncoding()))), record -> logger.log(Level.INFO, "record = " + record.toString(Charset.forName(client.getEncoding()))),
() -> logger.log(Level.WARNING, "timeout")); () -> logger.log(Level.WARNING, "timeout"));
logger.log(Level.INFO, "returned records = " + count); logger.log(Level.INFO, "returned records = " + count);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e); logger.log(Level.SEVERE, e.getMessage(), e);
}
} }
} }

View file

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

View file

@ -5,7 +5,7 @@ plugins {
dependencies { dependencies {
api project(':z3950-api') api project(':z3950-api')
api "org.xbib:cql-common:${project.property('xbib-cql.version')}" api libs.cql.common
} }
sourceSets { sourceSets {

View file

@ -1,5 +1,6 @@
package org.xbib.z3950.common; package org.xbib.z3950.common;
import java.nio.charset.StandardCharsets;
import org.xbib.z3950.api.Record; import org.xbib.z3950.api.Record;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -37,4 +38,9 @@ public class DefaultRecord implements Record {
public String toString(Charset charset) { public String toString(Charset charset) {
return new String(content, charset); return new String(content, charset);
} }
@Override
public String toString() {
return toString(StandardCharsets.UTF_8);
}
} }

14
z3950-groovy/build.gradle Normal file
View file

@ -0,0 +1,14 @@
apply from: rootProject.file('gradle/compile/groovy.gradle')
dependencies {
api project(':z3950-client-jdk')
api libs.groovy.xml
testRuntimeOnly libs.junit.jupiter.vintage
testImplementation libs.groovy
testImplementation libs.groovy.json
testImplementation libs.groovy.nio
testImplementation libs.groovy.sql
testImplementation libs.groovy.macro
testImplementation libs.groovy.templates
testImplementation libs.groovy.test
}

View file

@ -0,0 +1,35 @@
package org.xbib.z3950.groovy
import groovy.util.logging.Log
import org.junit.jupiter.api.Test
import org.xbib.z3950.client.jdk.JDKZClient
import java.util.logging.Level
@Log
class COPACTest {
@Test
void testCOPAC() {
String host = "z3950.copac.ac.uk"
int port = 210
String database = "COPAC"
String query = "@attr 1=1 smith"
// "1.2.840.10003.5.10"; // MARC
String preferredRecordSyntax = "1.2.840.10003.5.109.10" // xml
int from = 1
int length = 1
JDKZClient client = JDKZClient.builder()
.setHost(host)
.setPort(port)
.setDatabases(Collections.singletonList(database))
.setPreferredRecordSyntax(preferredRecordSyntax)
.build()
client.withCloseable {cl ->
cl.searchPQF(query, from, length,
(status, total, returned, elapsedMillis) -> log.log(Level.INFO, "total records = " + total),
record -> log.log(Level.INFO, "found record " + record), // MODS
() -> log.log(Level.WARNING, "timeout"))
}
}
}