diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..9a5a1c9c2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" + groups: + minor-and-patch: + applies-to: version-updates + update-types: + - "patch" + - "minor" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a7a1822d0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: java -# Javadoc exclusions don't work with JDK 1.7. -script: mvn -Dmaven.javadoc.skip=true clean verify -jdk: -- oraclejdk8 -- openjdk7 -- openjdk8 - -# suggested by travis support. -sudo: required -dist: trusty -group: - -sudo: required diff --git a/CI.Jenkinsfile b/CI.Jenkinsfile new file mode 100644 index 000000000..6d669cfba --- /dev/null +++ b/CI.Jenkinsfile @@ -0,0 +1,60 @@ +node ("docker-light") { + def sourceDir = pwd() + try { + env.JAVA_HOME = "${tool 'java21'}" + env.PATH = "${env.JAVA_HOME}/bin:${env.PATH}" + def mavenLocalRepo = "$JENKINS_HOME/maven-local-repositories/executor-$EXECUTOR_NUMBER" + stage("Clean up") { + step([$class: 'WsCleanup']) + sh "rm -rf $mavenLocalRepo" + } + stage("Checkout Code") { + checkout scm + } + stage("Build") { + withMaven(maven: "Basis", + mavenLocalRepo: mavenLocalRepo, + publisherStrategy: "EXPLICIT") { + sh "mvn clean verify" + } + + } + stage("Test with Docker") { + withSonarQubeEnv { + mySonarOpts="-Dsonar.login=${env.SONAR_AUTH_TOKEN} -Dsonar.host.url=${env.SONAR_HOST_URL}" + if ("${env.CHANGE_BRANCH}" != "null") { + mySonarOpts="$mySonarOpts -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH}" + } + echo("Sonar Options are: $mySonarOpts") + sh "docker run --rm \ + --pull always \ + --volume ${sourceDir}:/source \ + --volume /opt/maven-basis:/opt/maven-basis \ + eclipse-temurin:21-jdk-noble \ + bash -c \"apt-get update && \ + apt-get install -y git && \ + pushd /source && \ + git config --global --add safe.directory /source && \ + /opt/maven-basis/bin/mvn --batch-mode clean install sonar:sonar $mySonarOpts; \ + maven_ret=\\\$?; \ + echo && \ + echo [INFO] Set file permissions to UID and GID of jenkins user for cleanup. && \ + chown -R 9960:9960 /source && \ + exit \\\$maven_ret\"" + } + } + postToTeams(true) + } catch (e) { + currentBuild.result = "FAILED" + postToTeams(false) + throw e + } +} + +def postToTeams(boolean success) { + def webhookUrl = "${env.TEAMS_PNC_JENKINS_WEBHOOK_URL}" + def color = success ? "#00FF00" : "#FF0000" + def status = success ? "SUCCESSFUL" : "FAILED" + def message = "*" + status + ":* '${env.JOB_NAME}' - [${env.BUILD_NUMBER}] - ${env.BUILD_URL}" + office365ConnectorSend(webhookUrl: webhookUrl, color: color, message: message, status: status) +} diff --git a/DEVELOPER.md b/DEVELOPER.md new file mode 100644 index 000000000..e733bfd8e --- /dev/null +++ b/DEVELOPER.md @@ -0,0 +1,18 @@ +## Developer Notes + +#### Deprecation Strategies +If we remove a field via deprecation, the field can still be passed in, but we will no longer deserialize it. As an example see [PR 204](https://github.com/rosette-api/java/pull/204). + +#### Building and Releasing +To be updated.. + + +#### Internal Releasing + +To perform an internal release, execute the following commands: +``` +$ mvn release:clean +$ mvn release:prepare +$ mvn release:perform -Drelease-profile=internal-release +``` + diff --git a/Jenkinsfile b/Jenkinsfile index 735084372..5777d9641 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,30 +1,43 @@ node ("docker-light") { def SOURCEDIR = pwd() try { + env.JAVA_HOME = "${tool 'java21'}" + env.PATH = "${env.JAVA_HOME}/bin:${env.PATH}" + def mavenLocalRepo = "$JENKINS_HOME/maven-local-repositories/executor-$EXECUTOR_NUMBER" stage("Clean up") { step([$class: 'WsCleanup']) + sh "rm -rf $mavenLocalRepo" } stage("Checkout Code") { checkout scm } + stage("Build") { + withMaven(maven: "Basis", + mavenLocalRepo: mavenLocalRepo, + publisherStrategy: "EXPLICIT") { + sh "mvn clean verify" + } + + } stage("Test with Docker") { echo "${env.ALT_URL}" def useUrl = ("${env.ALT_URL}" == "null") ? "${env.BINDING_TEST_URL}" : "${env.ALT_URL}" withEnv(["API_KEY=${env.ROSETTE_API_KEY}", "ALT_URL=${useUrl}"]) { - sh "docker run --rm -e API_KEY=${API_KEY} -e ALT_URL=${ALT_URL} -v ${SOURCEDIR}:/source rosetteapi/docker-java" + sh "docker run --rm -e API_KEY=${API_KEY} -e ALT_URL=${ALT_URL} -v ${SOURCEDIR}:/source rosette/docker-java" } } - slack(true) + postToTeams(true) } catch (e) { currentBuild.result = "FAILED" - slack(false) + postToTeams(false) throw e } } -def slack(boolean success) { +def postToTeams(boolean success) { + def webhookUrl = "${env.TEAMS_PNC_JENKINS_WEBHOOK_URL}" def color = success ? "#00FF00" : "#FF0000" def status = success ? "SUCCESSFUL" : "FAILED" - def message = status + ": Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})" - slackSend(color: color, channel: "#rapid", message: message) -} \ No newline at end of file + def message = "*" + status + ":* '${env.JOB_NAME}' - [${env.BUILD_NUMBER}] - ${env.BUILD_URL}" + office365ConnectorSend(webhookUrl: webhookUrl, color: color, message: message, status: status) +} diff --git a/Jenkinsfile.examples b/Jenkinsfile.examples index d0b8d4246..fad51cfde 100644 --- a/Jenkinsfile.examples +++ b/Jenkinsfile.examples @@ -22,17 +22,18 @@ node { sh "docker run --rm -e API_KEY=${API_KEY} -e ALT_URL=${ALT_URL} -e VERSION=${PUBLISHED_VERSION} -v ${SOURCEDIR}:/source ${TEST_CONTAINER}" } } - slack(true) + postToTeams(true) } catch (e) { currentBuild.result = "FAILED" - slack(false) + postToTeams(false) throw e } } -def slack(boolean success) { +def postToTeams(boolean success) { + def webhookUrl = "${env.TEAMS_PNC_JENKINS_WEBHOOK_URL}" def color = success ? "#00FF00" : "#FF0000" def status = success ? "SUCCESSFUL" : "FAILED" - def message = status + ": Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})" - slackSend(color: color, channel: "#rapid", message: message) -} \ No newline at end of file + def message = "*" + status + ":* '${env.JOB_NAME}' - [${env.BUILD_NUMBER}] - ${env.BUILD_URL}" + office365ConnectorSend(webhookUrl: webhookUrl, color: color, message: message, status: status) +} diff --git a/README.md b/README.md index c7b230706..a15ed7735 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,35 @@ -[![Build Status](https://travis-ci.org/rosette-api/java.svg?branch=master)](https://travis-ci.org/rosette-api/java) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.basistech.rosette/rosette-api-java-binding/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.basistech.rosette/rosette-api-java-binding) + + + + + Babel Street Logo + + -# Java client binding for Rosette API # +# Analytics by Babel Street -## Installation ## -If you use Maven, include this dependency in your `pom.xml`: +--- +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.basistech.rosette/rosette-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.basistech.rosette/rosette-api-java-binding) + +Our product is a full text processing pipeline from data preparation to extracting the most relevant information and +analysis utilizing precise, focused AI that has built-in human understanding. Text Analytics provides foundational +linguistic analysis for identifying languages and relating words. The result is enriched and normalized text for +high-speed search and processing without translation. + +Text Analytics extracts events and entities — people, organizations, and places — from unstructured text and adds the +structure of associating those entities into events that deliver only the necessary information for near real-time +decision making. Accompanying tools shorten the process of training AI models to recognize domain-specific events. + +The product delivers a multitude of ways to sharpen and expand search results. Semantic similarity expands search +beyond keywords to words with the same meaning, even in other languages. Sentiment analysis and topic extraction help +filter results to what’s relevant. + +## Analytics API Access +- Analytics Cloud [Sign Up](https://developer.babelstreet.com/signup) +## Quick Start + +#### Maven ```xml com.basistech.rosette @@ -14,35 +38,25 @@ If you use Maven, include this dependency in your `pom.xml`: ``` -where `${rosette.api.java.binding.version}` is the [latest version available from Maven Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.basistech.rosette%22%20AND%20a%3A%22rosette-api%22). - -The version will change as new versions of the binding are released. Note that versions of the form `x.y.Nxx`, where `N` is greater than 100, are internal testing versions; do not use them without consultation with Basis Technology Corp. - -If the version you are using is not the latest from Maven Central. Please check for its -[**compatibilty with api.rosette.com**](https://developer.rosette.com/features-and-functions?java). -If you have an on-premise version of Rosette API server, please contact support for binding -compatibility with your installation. - -The source code on the master branch is the current state of development; it is not recommended for general use. -If you prefer to build from source, please use an appropriate release tag. - -## Basic Usage ## -To check out more examples, see [examples](examples/src/main/java/com/basistech/rosette/examples) - -## API Documentation ## -Check out the [documentation](http://rosette-api.github.io/java) +Set `${rosette.api.java.binding.version}` in the `` block. The latest version available is displayed +in the Maven Central badge at the top of this page. -## Release Notes -See the [Wiki](https://github.com/rosette-api/java/wiki/Release-Notes). +#### Test Releases +Versions, of the form `x.y.z`, where `z` is greater than or equal to `100`, are internal testing versions. Do not use +them without consultation with Babel Street. -## Docker ## -A Docker image for running the examples against the compiled source library is available on Docker Hub. +#### Examples +View small example programs for each Analytics endpoint in the +[examples](examples/src/main/java/com/basistech/rosette/examples) directory. -Command: `docker run -e API_KEY=api-key -v ":/source" rosetteapi/docker-java` +#### Documentation & Support +- [Binding API](https://rosette-api.github.io/java/) +- [Analytics Platform API](https://docs.babelstreet.com/API/en/index-en.html) +- [Binding Release Notes](https://github.com/rosette-api/java/wiki/Release-Notes) +- [Analytics Platform Release Notes](https://docs.babelstreet.com/Release/en/rosette-cloud.html) +- [Support](https://babelstreet.my.site.com/support/s/) +- [Binding License: Apache 2.0](LICENSE.txt) -Additional environment settings: -`-e ALT_URL=` -`-e FILENAME=` +## Binding Developer Information +If you are modifying the binding code, please refer to the [developer README](DEVELOPER.md) file. -## Additional Information ## -For more, visit [Rosette API site](https://developer.rosette.com) diff --git a/all/pom.xml b/all/pom.xml new file mode 100644 index 000000000..430805806 --- /dev/null +++ b/all/pom.xml @@ -0,0 +1,109 @@ + + + + 4.0.0 + + com.basistech.rosette + rosette-api-java-binding + 1.36.1-SNAPSHOT + + rosette-api-all + rosette-api-all + Babel Street Analytics API all modules combined + + + com.basistech + common-api + + + com.basistech.rosette + rosette-api + ${project.version} + + + com.fasterxml.jackson.core + jackson-databind + + + com.basistech + adm-json + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + package + + add-source + + + + ../model/target/delombok + ../api/src/main/java + ../annotations/src/main/java + + + + + + + maven-javadoc-plugin + + ../model/target/delombok;../api/src/main/java + + + com.basistech.rosette + rosette-api-annotations + ${project.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + shade + + shade + + package + + true + + + com.basistech.* + + + + + + + + + diff --git a/annotations/bnd.bnd b/annotations/bnd.bnd deleted file mode 100644 index 099e137e3..000000000 --- a/annotations/bnd.bnd +++ /dev/null @@ -1,2 +0,0 @@ -Bundle-Version: ${osgi-version} -Export-Package: com.basistech.rosette.annotations diff --git a/annotations/pom.xml b/annotations/pom.xml index 78d7584c5..4b06d860d 100644 --- a/annotations/pom.xml +++ b/annotations/pom.xml @@ -1,6 +1,6 @@ + + commons-codec + commons-codec + ${commons-codec.version} + org.apache.httpcomponents httpclient - ${http-components-version} + ${bt-httpclient-version} + + + commons-codec + commons-codec + + org.apache.httpcomponents httpmime - ${http-components-version} - - - com.google.guava - guava - compile + ${bt-httpmime-version} + + + org.apache.httpcomponents + httpclient + + org.slf4j slf4j-api - junit - junit - - - org.mock-server - mockserver-client-java - ${mockserver-version} + org.junit.jupiter + junit-jupiter + ${junit.version} test org.mock-server - mockserver-core - ${mockserver-version} - test - - - org.mock-server - mockserver-netty - ${mockserver-version} + mockserver-junit-jupiter-no-dependencies + ${mockserver.version} test @@ -100,70 +103,9 @@ - - biz.aQute.bnd - bnd-maven-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - - - - org.codehaus.mojo - build-helper-maven-plugin - ${build-helper-maven-plugin.version} - - - reserve-network-port - - reserve-network-port - - initialize - - - mockServerClient.port - - - - - - - org.mock-server - mockserver-maven-plugin - ${mockserver-version} - - ${mockServerClient.port} - WARN - ${skip-mockserver} - - - - process-test-classes - process-test-classes - - runForked - - - - verify - verify - - stopForked - - - - org.apache.maven.plugins maven-surefire-plugin - - -Xmx1024m - @@ -176,13 +118,6 @@ - - src/test/resources - - **/*.property - - true - src/test/resources @@ -194,24 +129,4 @@ - - - skip-mockserver-tests - - true - - - - - - maven-surefire-plugin - - true - - - - - - - diff --git a/api/src/main/java/com/basistech/rosette/api/HttpRosetteAPI.java b/api/src/main/java/com/basistech/rosette/api/HttpRosetteAPI.java index 4bf8a8f10..b0e997b90 100644 --- a/api/src/main/java/com/basistech/rosette/api/HttpRosetteAPI.java +++ b/api/src/main/java/com/basistech/rosette/api/HttpRosetteAPI.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.basistech.rosette.apimodel.PingResponse; import com.basistech.rosette.apimodel.Request; import com.basistech.rosette.apimodel.Response; +import com.basistech.rosette.apimodel.SupportedLanguagePairsResponse; import com.basistech.rosette.apimodel.SupportedLanguagesResponse; import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; import com.basistech.rosette.apimodel.jackson.DocumentRequestMixin; @@ -34,7 +35,6 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; -import com.google.common.io.ByteStreams; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHeaders; @@ -60,6 +60,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -72,20 +73,24 @@ import java.util.Properties; import java.util.Set; import java.util.concurrent.Future; +import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import static java.net.HttpURLConnection.HTTP_OK; /** - * Access to the RosetteAPI via HTTP. + * Access to the Analytics API via HTTP. */ public class HttpRosetteAPI extends AbstractRosetteAPI { - public static final String DEFAULT_URL_BASE = "https://api.rosette.com/rest/v1"; - public static final String SERVICE_NAME = "RosetteAPI"; + public static final String DEFAULT_URL_BASE = "https://analytics.babelstreet.com/rest/v1"; + public static final String SERVICE_NAME = "Babel-Street-Analytics-API"; public static final String BINDING_VERSION = getVersion(); - public static final String USER_AGENT_STR = SERVICE_NAME + "-Java/" + BINDING_VERSION + "/" + System.getProperty("java.version"); + public static final String USER_AGENT_STR = SERVICE_NAME + "-Java/" + BINDING_VERSION + "/" + + System.getProperty("java.version"); private static final Logger LOG = LoggerFactory.getLogger(HttpRosetteAPI.class); + private static final String IO_EXCEPTION_MESSAGE = "IO Exception communicating with the Babel Street Analytics API"; + private static final Pattern TRAILING_SLASHES = Pattern.compile("/+$"); private String urlBase = DEFAULT_URL_BASE; private int failureRetries = 1; private ObjectMapper mapper; @@ -99,23 +104,23 @@ private HttpRosetteAPI() { } /** - * Constructs a Rosette API instance using the builder syntax. + * Constructs an Analytics API instance using the builder syntax. * - * @param key Rosette API key. This may be null for use with an on-premise deployment - * of the Rosette API. - * @param urlToCall Alternate Rosette API URL. {@code null} uses the default, public, URL. + * @param key Analytics API key. This may be null for use with an on-premise deployment + * of the Analytics API. + * @param urlToCall Alternate Analytics API URL. {@code null} uses the default, public, URL. * @param failureRetries Number of times to retry in case of failure; {@code null} uses the * default value: 1. * @param connectionConcurrency Number of concurrent connections. Pass this if have subscribed * to a plan that supports enhanced concurrency, or if you are using - * an on-premise deployment of the Rosette API. {@code null} uses the + * an on-premise deployment of the Analytics API. {@code null} uses the * default value: 2. * @throws HttpRosetteAPIException Problem with the API request */ HttpRosetteAPI(String key, String urlToCall, Integer failureRetries, CloseableHttpClient httpClient, List
additionalHeaders, Integer connectionConcurrency, boolean onlyAcceptKnownFields) throws HttpRosetteAPIException { - urlBase = urlToCall == null ? urlBase : urlToCall.trim().replaceAll("/+$", ""); + urlBase = urlToCall == null ? urlBase : TRAILING_SLASHES.matcher(urlToCall.trim()).replaceAll(""); if (failureRetries != null && failureRetries >= 1) { this.failureRetries = failureRetries; } @@ -158,13 +163,26 @@ private static String getVersion() { * @throws IOException */ private static byte[] getBytes(InputStream is) throws IOException { - return ByteStreams.toByteArray(is); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + byte[] buf = new byte[4096]; + + while (true) { + int r = is.read(buf); + if (r == -1) { + out.flush(); + return out.toByteArray(); + } + out.write(buf, 0, r); + } } + @SuppressWarnings("java:HttpClient_must_be_closed") // This library requires keeping the connection open. private void initClient(String key, List
additionalHeaders) { HttpClientBuilder builder = HttpClients.custom(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(connectionConcurrency); + cm.setDefaultMaxPerRoute(connectionConcurrency); builder.setConnectionManager(cm); initHeaders(key, additionalHeaders); @@ -179,7 +197,10 @@ private void initHeaders(String key, List
additionalHeaders) { this.additionalHeaders.add(new BasicHeader(HttpHeaders.USER_AGENT, USER_AGENT_STR)); this.additionalHeaders.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip")); if (key != null) { - this.additionalHeaders.add(new BasicHeader("X-RosetteAPI-Key", key)); + this.additionalHeaders.add(new BasicHeader("X-BabelStreetAPI-Key", key)); + this.additionalHeaders.add(new BasicHeader("X-BabelStreetAPI-Binding", "java")); + this.additionalHeaders.add(new BasicHeader("X-BabelStreetAPI-Binding-Version", BINDING_VERSION)); + // TODO: Remove in a future release. this.additionalHeaders.add(new BasicHeader("X-RosetteAPI-Binding", "java")); this.additionalHeaders.add(new BasicHeader("X-RosetteAPI-Binding-Version", BINDING_VERSION)); } @@ -198,10 +219,10 @@ public int getFailureRetries() { } /** - * Gets information about the Rosette API, returns name, version, build number and build time. + * Gets information about the Analytics API, returns name, version, build number and build time. * * @return InfoResponse - * @throws HttpRosetteAPIException Rosette specific exception + * @throws HttpRosetteAPIException Analytics specific exception * @throws IOException General IO exception */ public InfoResponse info() throws IOException, HttpRosetteAPIException { @@ -209,10 +230,10 @@ public InfoResponse info() throws IOException, HttpRosetteAPIException { } /** - * Pings the Rosette API for a response indicating that the service is available. + * Pings the Analytics API for a response indicating that the service is available. * * @return PingResponse - * @throws HttpRosetteAPIException Rosette specific exception + * @throws HttpRosetteAPIException Analytics specific exception * @throws IOException General IO exception */ public PingResponse ping() throws IOException, HttpRosetteAPIException { @@ -220,15 +241,34 @@ public PingResponse ping() throws IOException, HttpRosetteAPIException { } /** - * Gets the set of language and script codes supported by the specified Rosette API endpoint. + * Gets the set of language and script codes supported by the specified Analytics API endpoint. * * @return SupportedLanguagesResponse - * @throws HttpRosetteAPIException for an error returned from the Rosette API. + * @throws HttpRosetteAPIException for an error returned from the Analytics API. */ @Override public SupportedLanguagesResponse getSupportedLanguages(String endpoint) throws HttpRosetteAPIException { - if (DOC_ENDPOINTS.contains(endpoint)) { - return sendGetRequest(urlBase + endpoint + SUPPORTED_LANGUAGES_SUBPATH, SupportedLanguagesResponse.class); + if (DOC_ENDPOINTS.contains(endpoint) || NAME_DEDUPLICATION_SERVICE_PATH.equals(endpoint)) { + return sendGetRequest(urlBase + endpoint + SUPPORTED_LANGUAGES_SUBPATH, + SupportedLanguagesResponse.class); + } else { + return null; + } + } + + /** + * Gets the set of language, script codes and transliteration scheme pairs supported by the specified Analytics API + * endpoint. + * + * @param endpoint Analytics API endpoint. + * @return SupportedLanguagePairsResponse + * @throws HttpRosetteAPIException for an error returned from the Analytics API. + */ + @Override + public SupportedLanguagePairsResponse getSupportedLanguagePairs(String endpoint) throws HttpRosetteAPIException { + if (NAMES_ENDPOINTS.contains(endpoint) && !NAME_DEDUPLICATION_SERVICE_PATH.equals(endpoint)) { + return sendGetRequest(urlBase + endpoint + SUPPORTED_LANGUAGES_SUBPATH, + SupportedLanguagePairsResponse.class); } else { return null; } @@ -242,15 +282,16 @@ public SupportedLanguagesResponse getSupportedLanguages(String endpoint) throws * @param the type of the request object. * @param the type of the response object. * @return the response. - * @throws HttpRosetteAPIException for an error returned from the Rosette API. + * @throws HttpRosetteAPIException for an error returned from the Analytics API. * @throws RosetteRuntimeException for other errors, such as communications problems with HTTP. */ @Override - public ResponseType perform(String endpoint, RequestType request, Class responseClass) throws HttpRosetteAPIException { + public ResponseType perform(String endpoint, + RequestType request, Class responseClass) throws HttpRosetteAPIException { try { return sendPostRequest(request, urlBase + endpoint, responseClass); } catch (IOException e) { - throw new RosetteRuntimeException("IO Exception communicating with the Rosette API", e); + throw new RosetteRuntimeException(IO_EXCEPTION_MESSAGE, e); } catch (URISyntaxException e) { throw new RosetteRuntimeException("Invalid URI", e); } @@ -262,15 +303,16 @@ public ResponseType * @param request the data for the request. * @param the type of the request object. * @return the response, {@link com.basistech.rosette.dm.AnnotatedText}. - * @throws HttpRosetteAPIException for an error returned from the Rosette API. + * @throws HttpRosetteAPIException for an error returned from the Analytics API. * @throws RosetteRuntimeException for other errors, such as communications problems with HTTP. */ @Override - public AnnotatedText perform(String endpoint, RequestType request) throws HttpRosetteAPIException { + public AnnotatedText perform(String endpoint, RequestType request) + throws HttpRosetteAPIException { try { return sendPostRequest(request, urlBase + endpoint, AnnotatedText.class); } catch (IOException e) { - throw new RosetteRuntimeException("IO Exception communicating with the Rosette API", e); + throw new RosetteRuntimeException(IO_EXCEPTION_MESSAGE, e); } catch (URISyntaxException e) { throw new RosetteRuntimeException("Invalid URI", e); } @@ -280,16 +322,18 @@ public AnnotatedText perform(String endpoint, Requ * This method always throws UnsupportedOperationException. */ @Override - public Future performAsync(String endpoint, RequestType request, Class responseClass) throws HttpRosetteAPIException { + public Future + performAsync(String endpoint, RequestType request, Class responseClass) + throws HttpRosetteAPIException { throw new UnsupportedOperationException("Asynchronous operations are not yet supported"); } /** - * Sends a GET request to Rosette API. + * Sends a GET request to Analytics API. *

* Returns a Response. * - * @param urlStr Rosette API end point. + * @param urlStr Analytics API end point. * @param clazz Response class * @return Response * @throws HttpRosetteAPIException @@ -305,21 +349,22 @@ private T sendGetRequest(String urlStr, Class clazz) thr responseHeadersToExtendedInformation(resp, httpResponse); return resp; } catch (IOException e) { - throw new RosetteRuntimeException("IO Exception communicating with the Rosette API", e); + throw new RosetteRuntimeException(IO_EXCEPTION_MESSAGE, e); } } /** - * Sends a POST request to Rosette API. + * Sends a POST request to Analytics API. *

* Returns a Response. * - * @param urlStr Rosette API end point. + * @param urlStr Analytics API end point. * @param clazz Response class * @return Response * @throws IOException */ - private T sendPostRequest(Object request, String urlStr, Class clazz) throws IOException, URISyntaxException { + private T sendPostRequest(Object request, String urlStr, Class clazz) + throws IOException, URISyntaxException { ObjectWriter writer = mapper.writer().without(JsonGenerator.Feature.AUTO_CLOSE_TARGET); boolean notPlainText = false; if (request instanceof DocumentRequest) { @@ -359,9 +404,14 @@ private T sendPostRequest(Object request, String urlStr, Class clazz) thr while (numRetries-- > 0) { try (CloseableHttpResponse response = httpClient.execute(post)) { T resp = getResponse(response, clazz); + // TODO: Remove in a future release Header ridHeader = response.getFirstHeader("X-RosetteAPI-DocumentRequest-Id"); if (ridHeader != null && ridHeader.getValue() != null) { - LOG.debug("DocumentRequest ID " + ridHeader.getValue()); + LOG.debug("DocumentRequest ID {}", ridHeader.getValue()); + } + Header bsidHeader = response.getFirstHeader("X-BabelStreetAPI-DocumentRequest-Id"); + if (bsidHeader != null && bsidHeader.getValue() != null) { + LOG.debug("DocumentRequest ID {}", bsidHeader.getValue()); } if (resp instanceof Response) { responseHeadersToExtendedInformation((Response)resp, response); @@ -388,7 +438,8 @@ private void responseHeadersToExtendedInformation(T resp, H if (resp.getExtendedInformation().get(header.getName()) instanceof Set) { currentSetValue = (Set) resp.getExtendedInformation().get(header.getName()); } else { - currentSetValue = new HashSet<>(Collections.singletonList(resp.getExtendedInformation().get(header.getName()))); + currentSetValue = new HashSet<>(Collections.singletonList(resp + .getExtendedInformation().get(header.getName()))); } currentSetValue.add(header.getValue()); resp.addExtendedInformation(header.getName(), currentSetValue); @@ -429,7 +480,8 @@ public boolean isStreaming() { }); } - private void setupMultipartRequest(final Request request, final ObjectWriter finalWriter, HttpPost post) throws IOException { + private void setupMultipartRequest(final Request request, final ObjectWriter finalWriter, HttpPost post) + throws IOException { MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMimeSubtype("mixed"); builder.setMode(HttpMultipartMode.STRICT); @@ -503,7 +555,8 @@ private String headerValueOrNull(Header header) { * @return Response * @throws IOException */ - private T getResponse(HttpResponse httpResponse, Class clazz) throws IOException, HttpRosetteAPIException { + private T getResponse(HttpResponse httpResponse, Class clazz) + throws IOException, HttpRosetteAPIException { int status = httpResponse.getStatusLine().getStatusCode(); String encoding = headerValueOrNull(httpResponse.getFirstHeader(HttpHeaders.CONTENT_ENCODING)); @@ -511,22 +564,39 @@ private T getResponse(HttpResponse httpResponse, Class cla InputStream stream = httpResponse.getEntity().getContent(); InputStream inputStream = "gzip".equalsIgnoreCase(encoding) ? new GZIPInputStream(stream) : stream) { String ridHeader = headerValueOrNull(httpResponse.getFirstHeader("X-RosetteAPI-DocumentRequest-Id")); + String bsidHeader = headerValueOrNull(httpResponse.getFirstHeader("X-BabelStreetAPI-DocumentRequest-Id")); if (HTTP_OK != status) { - String ecHeader = headerValueOrNull(httpResponse.getFirstHeader("X-RosetteAPI-Status-Code")); - String emHeader = headerValueOrNull(httpResponse.getFirstHeader("X-RosetteAPI-Status-Message")); + String ecHeader; + if (headerValueOrNull(httpResponse.getFirstHeader("X-BabelStreetAPI-Status-Code")) != null) { + ecHeader = headerValueOrNull(httpResponse.getFirstHeader("X-BabelStreetAPI-Status-Code")); + } else { + // TODO: Remove in a future release + ecHeader = headerValueOrNull(httpResponse.getFirstHeader("X-RosetteAPI-Status-Code")); + } + String emHeader; + if (headerValueOrNull(httpResponse.getFirstHeader("X-BabelStreetAPI-Status-Message")) != null) { + emHeader = headerValueOrNull(httpResponse.getFirstHeader("X-BabelStreetAPI-Status-Message")); + } else { + // TODO: Remove in a future release + emHeader = headerValueOrNull(httpResponse.getFirstHeader("X-RosetteAPI-Status-Message")); + } String responseContentType = headerValueOrNull(httpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE)); if ("application/json".equals(responseContentType)) { ErrorResponse errorResponse = mapper.readValue(inputStream, ErrorResponse.class); if (ridHeader != null) { - LOG.debug("DocumentRequest ID " + ridHeader); + LOG.debug("DocumentRequest ID {}", ridHeader); + } + if (bsidHeader != null) { + LOG.debug("DocumentRequest ID {}", bsidHeader); } if (ecHeader != null) { errorResponse.setCode(ecHeader); } if (429 == status) { String concurrencyMessage = "You have exceeded your plan's limit on concurrent calls. " - + "This could be caused by multiple processes or threads making Rosette API calls in parallel, " - + "or if your httpClient is configured with higher concurrency than your plan allows."; + + "This could be caused by multiple processes or threads making Analytics API calls " + + "in parallel, or if your httpClient is configured with higher concurrency " + + "than your plan allows."; if (emHeader == null) { emHeader = concurrencyMessage; } else { @@ -555,6 +625,21 @@ private T getResponse(HttpResponse httpResponse, Class cla } } + /** + * Creates a RosetteRequest which can be sent concurrently through this HttpRosetteAPI + * + * @param endpoint the endpoint to which the request is sent to + * @param request the request object + * @param responseClass Response's class + * @return RosetteRequest which when started sends the predefined request through this http client + */ + public RosetteRequest createRosetteRequest(String endpoint, + Request request, + Class responseClass) { + return new RosetteRequest(this, request, endpoint, responseClass); + } + + @Override public void close() throws IOException { if (closeClientOnClose) { @@ -647,6 +732,7 @@ public Builder additionalHeader(String name, String value) { * Only process the response from server if all fields are recognized. If set and a new * field is returned in the response, exception will be thrown. * + * @param onlyAcceptKnownFields whether to accept known fields. * @return this. */ public Builder onlyAcceptKnownFields(boolean onlyAcceptKnownFields) { diff --git a/api/src/main/java/com/basistech/rosette/api/MorphologicalFeature.java b/api/src/main/java/com/basistech/rosette/api/MorphologicalFeature.java index c426fa5be..243169659 100644 --- a/api/src/main/java/com/basistech/rosette/api/MorphologicalFeature.java +++ b/api/src/main/java/com/basistech/rosette/api/MorphologicalFeature.java @@ -1,5 +1,5 @@ /* -* Copyright 2014 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package com.basistech.rosette.api; /** - * Specify which feature you want Rosette API Morphology endpoint to return. Specify COMPLETE for every feature. + * Specify which feature you want Analytics API Morphology endpoint to return. Specify COMPLETE for every feature. */ public enum MorphologicalFeature { COMPLETE("complete"), diff --git a/api/src/main/java/com/basistech/rosette/api/RosetteRequest.java b/api/src/main/java/com/basistech/rosette/api/RosetteRequest.java new file mode 100644 index 000000000..bf2f5598f --- /dev/null +++ b/api/src/main/java/com/basistech/rosette/api/RosetteRequest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2023 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.basistech.rosette.api; + +import com.basistech.rosette.apimodel.Request; +import com.basistech.rosette.apimodel.Response; + +import java.util.concurrent.Callable; + +/** + * This class encompasses a future request that can be sent concurrently + */ +public class RosetteRequest implements Callable { + private final HttpRosetteAPI api; + private final Request request; + private final String servicePath; + private final Class responseClass; + private Response response; + + RosetteRequest(HttpRosetteAPI api, + Request request, + String servicePath, Class responseClass) { + this.api = api; + this.request = request; + this.servicePath = servicePath; + this.responseClass = responseClass; + } + + @Override + public Response call() { + try { + this.response = api.perform(this.servicePath, this.request, this.responseClass); + } catch (HttpRosetteAPIException ex) { + this.response = ex.getErrorResponse(); + } + return this.response; + } + + public Response getResponse() { + return this.response; + } +} diff --git a/api/src/test/java/com/basistech/rosette/api/AbstractTest.java b/api/src/test/java/com/basistech/rosette/api/AbstractTest.java deleted file mode 100644 index 632272adb..000000000 --- a/api/src/test/java/com/basistech/rosette/api/AbstractTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Copyright 2014 Basis Technology Corp. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.basistech.rosette.api; - -import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Charsets; -import com.google.common.io.Resources; -import org.junit.Assert; -import org.junit.BeforeClass; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.zip.GZIPOutputStream; - -public abstract class AbstractTest extends Assert { - public static final String INFO_REPONSE = "{ \"buildNumber\": \"6bafb29d\", \"buildTime\": \"2015.10.08_10:19:26\", \"name\": " - + "\"RosetteAPI\", \"version\": \"0.7.0\", \"versionChecked\": true }"; - protected static int serverPort; - protected static ObjectMapper mapper; - - @BeforeClass - public static void before() throws IOException { - URL url = Resources.getResource("MockServerClientPort.property"); - String clientPort = Resources.toString(url, Charsets.UTF_8); - serverPort = Integer.parseInt(clientPort); - mapper = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - } - - protected static byte[] gzip(String text) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (GZIPOutputStream out = new GZIPOutputStream(baos)) { - out.write(text.getBytes(StandardCharsets.UTF_8)); - } - return baos.toByteArray(); - } - - -} diff --git a/api/src/test/java/com/basistech/rosette/api/BasicTest.java b/api/src/test/java/com/basistech/rosette/api/BasicTest.java index 8dc1cf81b..b06047a03 100644 --- a/api/src/test/java/com/basistech/rosette/api/BasicTest.java +++ b/api/src/test/java/com/basistech/rosette/api/BasicTest.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,26 +19,30 @@ import com.basistech.rosette.apimodel.AdmRequest; import com.basistech.rosette.apimodel.Response; import com.basistech.rosette.apimodel.SupportedLanguage; +import com.basistech.rosette.apimodel.SupportedLanguagePair; +import com.basistech.rosette.apimodel.SupportedLanguagePairsResponse; import com.basistech.rosette.apimodel.SupportedLanguagesResponse; import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; import com.basistech.rosette.dm.AnnotatedText; import com.basistech.util.ISO15924; import com.basistech.util.LanguageCode; +import com.basistech.util.TextDomain; +import com.basistech.util.TransliterationScheme; + import org.apache.commons.io.IOUtils; import org.apache.http.HttpHeaders; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockserver.client.server.MockServerClient; -import org.mockserver.junit.MockServerRule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockserver.client.MockServerClient; +import org.mockserver.junit.jupiter.MockServerExtension; import org.mockserver.model.Delay; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; import java.io.IOException; import java.io.InputStream; -import java.net.ServerSocket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Date; @@ -48,29 +52,21 @@ import com.fasterxml.jackson.databind.ObjectMapper; import static com.basistech.rosette.api.common.AbstractRosetteAPI.ENTITIES_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_SIMILARITY_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class BasicTest extends AbstractTest { - - @Rule - public MockServerRule mockServerRule = new MockServerRule(this, getFreePort()); +@ExtendWith(MockServerExtension.class) +class BasicTest { private MockServerClient mockServer; private HttpRosetteAPI api; - private static int getFreePort() { - try (ServerSocket socket = new ServerSocket(0)) { - serverPort = socket.getLocalPort(); - } catch (IOException e) { - fail("Failed to allocate a port"); - } - assertNotEquals(0, serverPort); - return serverPort; - } - - @Before - public void setup() { - mockServer.reset(); - // for version check call + @BeforeEach + public void setup(MockServerClient mockServer) { + this.mockServer = mockServer; } // an indirect way to show that connection pooling works @@ -79,7 +75,7 @@ public void setup() { // then set concurrent connections = 5, // run several requests again, showing they're executed in parallel @Test - public void testMultipleConnections() throws IOException, InterruptedException { + void testMultipleConnections() throws InterruptedException { int delayTime = 3; int numConnections = 5; @@ -95,7 +91,7 @@ public void testMultipleConnections() throws IOException, InterruptedException { // "before" case - send off (numConnections) requests, expect them to run serially api = new HttpRosetteAPI.Builder().connectionConcurrency(1) - .url(String.format("http://localhost:%d/rest/v1", serverPort)).build(); + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())).build(); Date d1 = new Date(); @@ -111,10 +107,10 @@ public void testMultipleConnections() throws IOException, InterruptedException { Date d2 = new Date(); - assert d2.getTime() - d1.getTime() > delayTime * numConnections * 1000; // at least as long as the delay in the request + assertTrue(d2.getTime() - d1.getTime() > delayTime * numConnections * 1000); // at least as long as the delay in the request api = new HttpRosetteAPI.Builder().connectionConcurrency(numConnections) - .url(String.format("http://localhost:%d/rest/v1", serverPort)) + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) .build(); d1 = new Date(); @@ -130,12 +126,11 @@ public void testMultipleConnections() throws IOException, InterruptedException { d2 = new Date(); - assert d2.getTime() - d1.getTime() < delayTime * numConnections * 1000; // less than (numConnections) serial requests - assert d2.getTime() - d1.getTime() > delayTime * 1000; // but at least as long as one + assertTrue(d2.getTime() - d1.getTime() < delayTime * numConnections * 1000); // less than (numConnections) serial requests + assertTrue(d2.getTime() - d1.getTime() > delayTime * 1000); // but at least as long as one } - @Test - public void testHeaders() throws Exception { + void testHeaders() throws Exception { mockServer.when(HttpRequest.request() .withMethod("GET") .withPath("/rest/v1/ping") @@ -143,32 +138,34 @@ public void testHeaders() throws Exception { .withHeader(HttpHeaders.USER_AGENT, HttpRosetteAPI.USER_AGENT_STR)) .respond(HttpResponse.response() .withHeader("Content-Type", "application/json") - .withHeader("X-RosetteAPI-Concurrency", "5") + .withHeader("X-BabelStreetAPI-Concurrency", "5") .withStatusCode(200) .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}", StandardCharsets.UTF_8)); api = new HttpRosetteAPI.Builder() .key("foo-key") - .url(String.format("http://localhost:%d/rest/v1", serverPort)) + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) .additionalHeader("X-Foo", "Bar") .build(); - api.ping(); + var resp = api.ping(); + assertEquals("5", resp.getExtendedInformation().get("X-BabelStreetAPI-Concurrency")); } @Test - public void testAdm() throws Exception { + void testAdm() throws Exception { try (InputStream reqIns = getClass().getResourceAsStream("/adm-req.json"); InputStream respIns = getClass().getResourceAsStream("/adm-resp.json")) { + assertNotNull(respIns); mockServer.when(HttpRequest.request() .withMethod("POST") .withPath("/rest/v1/entities")) .respond(HttpResponse.response() .withStatusCode(200) .withHeader("Content-Type", "application/json") - .withBody(IOUtils.toString(respIns, "UTF-8"))); + .withBody(IOUtils.toString(respIns, StandardCharsets.UTF_8))); api = new HttpRosetteAPI.Builder() .key("foo-key") - .url(String.format("http://localhost:%d/rest/v1", serverPort)) + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) .build(); AnnotatedText testData = ApiModelMixinModule.setupObjectMapper( new ObjectMapper()).readValue(reqIns, AnnotatedText.class); @@ -179,7 +176,7 @@ public void testAdm() throws Exception { } @Test - public void testExtendedInfo() throws Exception { + void testExtendedInfo() throws Exception { mockServer.when(HttpRequest.request() .withMethod("GET") .withPath("/rest/v1/ping")) @@ -188,11 +185,11 @@ public void testExtendedInfo() throws Exception { .withHeader("Content-Type", "application/json") .withHeader("X-Foo", "Bar") .withHeader("X-FooMulti", "Bar1", "Bar2") - .withHeader("X-RosetteAPI-Concurrency", "5") + .withHeader("X-BabelStreetAPI-Concurrency", "5") .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}", StandardCharsets.UTF_8)); api = new HttpRosetteAPI.Builder() .key("foo-key") - .url(String.format("http://localhost:%d/rest/v1", serverPort)) + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) .build(); Response resp = api.ping(); assertEquals("Bar", resp.getExtendedInformation().get("X-Foo")); @@ -201,10 +198,10 @@ public void testExtendedInfo() throws Exception { assertTrue(foos.contains("Bar2")); } - private class ApiPinger extends Thread { + private static class ApiPinger extends Thread { HttpRosetteAPI api1; - ApiPinger(HttpRosetteAPI api) throws IOException { + ApiPinger(HttpRosetteAPI api) { this.api1 = api; } @@ -219,28 +216,93 @@ public void run() { } @Test - public void testLanguageSupport() throws Exception { + void testLanguageSupport() throws Exception { try (InputStream respIns = getClass().getResourceAsStream("/supported-languages.json")) { + assertNotNull(respIns); mockServer.when(HttpRequest.request() .withMethod("GET") .withPath("/rest/v1/entities/supported-languages")) .respond(HttpResponse.response() .withStatusCode(200) .withHeader("Content-Type", "application/json") - .withBody(IOUtils.toString(respIns, "UTF-8"))); + .withBody(IOUtils.toString(respIns, StandardCharsets.UTF_8))); api = new HttpRosetteAPI.Builder() .key("foo-key") - .url(String.format("http://localhost:%d/rest/v1", serverPort)) + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) .build(); SupportedLanguagesResponse resp = api.getSupportedLanguages(ENTITIES_SERVICE_PATH); assertEquals(2, resp.getSupportedLanguages().size()); assertTrue(resp.getSupportedLanguages().contains(SupportedLanguage.builder() .language(LanguageCode.ENGLISH) .script(ISO15924.Latn) + .licensed(Boolean.TRUE) .build())); assertTrue(resp.getSupportedLanguages().contains(SupportedLanguage.builder() .language(LanguageCode.JAPANESE) .script(ISO15924.Kana) + .licensed(Boolean.FALSE) + .build())); + } + } + + @Test + void testNameSimilarityLanguageSupport() throws Exception { + try (InputStream respIns = getClass().getResourceAsStream("/name-similarity-supported-languages.json")) { + assertNotNull(respIns); + mockServer.when(HttpRequest.request() + .withMethod("GET") + .withPath("/rest/v1/name-similarity/supported-languages")) + .respond(HttpResponse.response() + .withStatusCode(200) + .withHeader("Content-Type", "application/json") + .withBody(IOUtils.toString(respIns, StandardCharsets.UTF_8))); + api = new HttpRosetteAPI.Builder() + .key("foo-key") + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) + .build(); + + SupportedLanguagePairsResponse resp = api.getSupportedLanguagePairs(NAME_SIMILARITY_SERVICE_PATH); + assertEquals(2, resp.getSupportedLanguagePairs().size()); + assertTrue(resp.getSupportedLanguagePairs().contains(SupportedLanguagePair.builder() + .source(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, null)) + .target(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, null)) + .licensed(Boolean.TRUE) + .build())); + assertTrue(resp.getSupportedLanguagePairs().contains(SupportedLanguagePair.builder() + .source(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, null)) + .target(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, null)) + .licensed(Boolean.TRUE) + .build())); + } + } + + @Test + void testNameTranslationLanguageSupport() throws Exception { + try (InputStream respIns = getClass().getResourceAsStream("/name-translation-supported-languages.json")) { + assertNotNull(respIns); + mockServer.when(HttpRequest.request() + .withMethod("GET") + .withPath("/rest/v1/name-translation/supported-languages")) + .respond(HttpResponse.response() + .withStatusCode(200) + .withHeader("Content-Type", "application/json") + .withBody(IOUtils.toString(respIns, StandardCharsets.UTF_8))); + api = new HttpRosetteAPI.Builder() + .key("foo-key") + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) + .build(); + + SupportedLanguagePairsResponse resp = api.getSupportedLanguagePairs(NAME_TRANSLATION_SERVICE_PATH); + assertEquals(2, resp.getSupportedLanguagePairs().size()); + assertTrue(resp.getSupportedLanguagePairs().contains(SupportedLanguagePair.builder() + .source(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, TransliterationScheme.NATIVE)) + .target(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, TransliterationScheme.IC)) + .licensed(Boolean.TRUE) + .build())); + assertTrue(resp.getSupportedLanguagePairs().contains(SupportedLanguagePair.builder() + .source(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, TransliterationScheme.NATIVE)) + .target(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, TransliterationScheme.NATIVE)) + .licensed(Boolean.TRUE) .build())); } } diff --git a/api/src/test/java/com/basistech/rosette/api/DevRosetteAPITest.java b/api/src/test/java/com/basistech/rosette/api/DevRosetteAPITest.java index ee9ad2a5a..16c6cb5ca 100644 --- a/api/src/test/java/com/basistech/rosette/api/DevRosetteAPITest.java +++ b/api/src/test/java/com/basistech/rosette/api/DevRosetteAPITest.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,42 +23,43 @@ import com.basistech.rosette.apimodel.TokensResponse; import com.basistech.util.LanguageCode; import com.basistech.util.PartOfSpeechTagSet; -import com.google.common.base.Charsets; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import java.io.IOException; +import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Test that is usually ignored, used to debug against a live service. */ -@org.junit.Ignore -public class DevRosetteAPITest { +@Disabled +class DevRosetteAPITest { // edit the right URL into place private static final String URL = "http://localhost:8181/rest/v1"; private static final String KEY = null; private HttpRosetteAPI api; - @Before - public void before() throws Exception { + @BeforeEach + public void before() { api = new HttpRosetteAPI.Builder().key(KEY).url(URL).build(); } - @After + @AfterEach public void after() throws IOException { api.close(); } @Test - public void multipart() throws Exception { + void multipart() { // this assumes that the server has the mock version of the components. Request morphologyRequest = DocumentRequest.builder().language(LanguageCode.ENGLISH) .options(MorphologyOptions.builder().partOfSpeechTagSet(PartOfSpeechTagSet.upt16).build()) - .content("This is the cereal shot from 1 gun .".getBytes(Charsets.UTF_8), "text/plain;charset=utf-8") + .content("This is the cereal shot from 1 gun .".getBytes(StandardCharsets.UTF_8), "text/plain;charset=utf-8") .build(); TokensResponse response = api.perform(AbstractRosetteAPI.TOKENS_SERVICE_PATH, morphologyRequest, TokensResponse.class); assertEquals(9, response.getTokens().size()); @@ -66,7 +67,7 @@ public void multipart() throws Exception { } @Test - public void simple() throws Exception { + void simple() { // this assumes that the server has the mock version of the components. Request morphologyRequest = DocumentRequest.builder().language(LanguageCode.ENGLISH) .options(MorphologyOptions.builder().partOfSpeechTagSet(PartOfSpeechTagSet.upt16).build()) diff --git a/api/src/test/java/com/basistech/rosette/api/InvalidErrorTest.java b/api/src/test/java/com/basistech/rosette/api/InvalidErrorTest.java index 3c57bcd75..045291788 100644 --- a/api/src/test/java/com/basistech/rosette/api/InvalidErrorTest.java +++ b/api/src/test/java/com/basistech/rosette/api/InvalidErrorTest.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,38 +20,52 @@ import com.basistech.rosette.apimodel.DocumentRequest; import com.basistech.rosette.apimodel.LanguageResponse; import org.apache.http.HttpHeaders; -import org.junit.Test; -import org.mockserver.client.server.MockServerClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockserver.client.MockServerClient; +import org.mockserver.junit.jupiter.MockServerExtension; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; import java.nio.charset.StandardCharsets; +import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static java.net.HttpURLConnection.HTTP_OK; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class InvalidErrorTest extends AbstractTest { +@ExtendWith(MockServerExtension.class) +class InvalidErrorTest { + private MockServerClient mockServer; + + @BeforeEach + public void setup(MockServerClient mockServer) { + this.mockServer = mockServer; + } @Test - public void notJsonError() throws Exception { - MockServerClient mockServer = new MockServerClient("localhost", serverPort); - mockServer.reset() - .when(HttpRequest.request().withPath(".*/{2,}.*")) + void notJsonError() throws Exception { + mockServer.when(HttpRequest.request().withPath(".*/{2,}.*")) .respond(HttpResponse.response() .withBody("Invalid path; '//'") - .withHeader("X-RosetteAPI-Concurrency", "5") - .withStatusCode(404)); + .withHeader("X-BabelStreetAPI-Concurrency", "5") + .withStatusCode(HTTP_NOT_FOUND)); mockServer.when(HttpRequest.request() .withMethod("GET") .withPath("/rest/v1/ping") .withHeader(HttpHeaders.USER_AGENT, HttpRosetteAPI.USER_AGENT_STR)) .respond(HttpResponse.response() .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}", StandardCharsets.UTF_8) - .withStatusCode(200) - .withHeader("X-RosetteAPI-Concurrency", "5")); - String mockServiceUrl = "http://localhost:" + Integer.toString(serverPort) + "/rest//v1"; + .withStatusCode(HTTP_OK) + .withHeader("X-BabelStreetAPI-Concurrency", "5")); + String mockServiceUrl = "http://localhost:" + mockServer.getPort() + "/rest//v1"; boolean exceptional = false; try { HttpRosetteAPI api = new HttpRosetteAPI.Builder().key("my-key-123").url(mockServiceUrl).build(); api.perform(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, DocumentRequest.builder().content("sample text").build(), LanguageResponse.class); + api.close(); } catch (HttpRosetteAPIException e) { exceptional = true; assertEquals("invalidErrorResponse", e.getErrorResponse().getCode()); @@ -59,5 +73,6 @@ public void notJsonError() throws Exception { assertNotNull(e.getErrorResponse().getMessage()); } assertTrue(exceptional); + mockServer.close(); } } diff --git a/api/src/test/java/com/basistech/rosette/api/RosetteAPITest.java b/api/src/test/java/com/basistech/rosette/api/RosetteAPITest.java index c32dad06b..d5ac9e058 100644 --- a/api/src/test/java/com/basistech/rosette/api/RosetteAPITest.java +++ b/api/src/test/java/com/basistech/rosette/api/RosetteAPITest.java @@ -1,5 +1,5 @@ /* -* Copyright 2014 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,11 @@ import com.basistech.rosette.RosetteRuntimeException; import com.basistech.rosette.api.common.AbstractRosetteAPI; +import com.basistech.rosette.apimodel.AddressSimilarityRequest; +import com.basistech.rosette.apimodel.AddressSimilarityResponse; import com.basistech.rosette.apimodel.CategoriesResponse; import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.EntitiesOptions; import com.basistech.rosette.apimodel.EntitiesResponse; import com.basistech.rosette.apimodel.ErrorResponse; import com.basistech.rosette.apimodel.LanguageResponse; @@ -30,476 +33,712 @@ import com.basistech.rosette.apimodel.NameSimilarityResponse; import com.basistech.rosette.apimodel.NameTranslationRequest; import com.basistech.rosette.apimodel.NameTranslationResponse; +import com.basistech.rosette.apimodel.SimilarTermsResponse; import com.basistech.rosette.apimodel.RelationshipsResponse; import com.basistech.rosette.apimodel.Request; import com.basistech.rosette.apimodel.SentimentResponse; import com.basistech.rosette.apimodel.SyntaxDependenciesResponse; +import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRequest; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityResponse; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.http.HttpHeaders; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.mockserver.client.server.MockServerClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockserver.client.MockServerClient; +import org.mockserver.junit.jupiter.MockServerExtension; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; - -@RunWith(Parameterized.class) -public class RosetteAPITest extends AbstractTest { - private final String testFilename; +import java.util.stream.Stream; +import java.util.zip.GZIPOutputStream; + +import static java.net.HttpURLConnection.HTTP_OK; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +@ExtendWith(MockServerExtension.class) +@SuppressWarnings("PMD.UnusedPrivateMethod") // Parameterized Tests +class RosetteAPITest { + private static final String INFO_RESPONSE = "{ \"buildNumber\": \"6bafb29d\", \"buildTime\": " + + "\"2015.10.08_10:19:26\", \"name\": \"RosetteAPI\", \"version\": \"0.7.0\", \"versionChecked\": true }"; private HttpRosetteAPI api; - private String responseStr; private MockServerClient mockServer; - private String mockServiceUrl = "http://localhost:" + Integer.toString(serverPort) + "/rest/v1"; + private ObjectMapper mapper; + - public RosetteAPITest(String filename) { - testFilename = filename; + @BeforeEach + public void setUp(MockServerClient mockServer) { + mapper = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + this.mockServer = mockServer; + this.mockServer.when(HttpRequest.request() + .withMethod("GET") + .withPath("/rest/v1/ping") + .withHeader(HttpHeaders.USER_AGENT, HttpRosetteAPI.USER_AGENT_STR)) + .respond(HttpResponse.response() + .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}", + StandardCharsets.UTF_8) + .withStatusCode(HTTP_OK) + .withHeader("X-BabelStreetAPI-Concurrency", "5")); + + this.mockServer.when(HttpRequest.request() + .withPath("/info")) + .respond(HttpResponse.response() + .withStatusCode(HTTP_OK) + .withHeader("Content-Type", "application/json") + .withHeader("X-BabelStreetAPI-Concurrency", "5") + .withBody(INFO_RESPONSE, StandardCharsets.UTF_8)); + + api = new HttpRosetteAPI.Builder() + .key("my-key-123") + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) + .build(); } - @Parameterized.Parameters - public static Collection data() throws URISyntaxException, IOException { - File dir = new File("src/test/mock-data/response"); - Collection params = new ArrayList<>(); - try (DirectoryStream paths = Files.newDirectoryStream(dir.toPath())) { - for (Path file : paths) { - if (file.toString().endsWith(".json")) { - params.add(new Object[]{file.getFileName().toString()}); - } - } + @AfterEach + public void reset() { + mockServer.reset(); + } + + private static byte[] gzip(String text) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (GZIPOutputStream out = new GZIPOutputStream(baos)) { + out.write(text.getBytes(StandardCharsets.UTF_8)); } - return params; + return baos.toByteArray(); } + private T readValue(Class clazz, String testFilename) throws IOException { + File input = new File("src/test/mock-data/request", testFilename); + return mapper.readValue(input, clazz); + } - @Before - public void setUp() throws Exception { - String statusFilename = testFilename.replace(".json", ".status"); - try (InputStream bodyStream = new FileInputStream("src/test/mock-data/response/" + testFilename)) { - responseStr = IOUtils.toString(bodyStream, "UTF-8"); - int statusCode = 200; + private void verifyException(HttpRosetteAPIException e, String responseStr) throws IOException { + ErrorResponse goldResponse = mapper.readValue(responseStr, ErrorResponse.class); + assertEquals(goldResponse.getCode(), e.getErrorResponse().getCode()); + } - File statusFile = new File("src/test/mock-data/response", statusFilename); - if (statusFile.exists()) { - String statusStr = FileUtils.readFileToString(statusFile, "UTF-8").trim(); - statusCode = Integer.parseInt(statusStr); - } - mockServer = new MockServerClient("localhost", serverPort); - mockServer.reset(); - mockServer.when(HttpRequest.request() - .withMethod("GET") - .withPath("/rest/v1/ping") - .withHeader(HttpHeaders.USER_AGENT, HttpRosetteAPI.USER_AGENT_STR)) + private void setStatusCodeResponse(String responseStr, int statusCode) throws IOException { + if (responseStr.length() > 200) { // test gzip if response is somewhat big + mockServer.when(HttpRequest.request().withPath("^(?!/info).+")) .respond(HttpResponse.response() - .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}", StandardCharsets.UTF_8) - .withStatusCode(200) - .withHeader("X-RosetteAPI-Concurrency", "5")); - if (responseStr.length() > 200) { // test gzip if response is somewhat big - mockServer.when(HttpRequest.request().withPath("^(?!/info).+")) - .respond(HttpResponse.response() - .withHeader("Content-Type", "application/json") - .withHeader("Content-Encoding", "gzip") - .withHeader("X-RosetteAPI-Concurrency", "5") - .withStatusCode(statusCode).withBody(gzip(responseStr))); - - } else { - mockServer.when(HttpRequest.request().withPath("^(?!/info).+")) - .respond(HttpResponse.response() - .withHeader("Content-Type", "application/json") - .withHeader("X-RosetteAPI-Concurrency", "5") - .withStatusCode(statusCode).withBody(responseStr, StandardCharsets.UTF_8)); + .withHeader("Content-Type", "application/json") + .withHeader("Content-Encoding", "gzip") + .withHeader("X-BabelStreetAPI-Concurrency", "5") + .withStatusCode(statusCode).withBody(gzip(responseStr))); + + } else { + mockServer.when(HttpRequest.request().withPath("^(?!/info).+")) + .respond(HttpResponse.response() + .withHeader("Content-Type", "application/json") + .withHeader("X-BabelStreetAPI-Concurrency", "5") + .withStatusCode(statusCode).withBody(responseStr, StandardCharsets.UTF_8)); + } + + } + + // Construct the parameters for our tests. We look inside the mock-data/response directory + // and gather any matching files. We read in the response string and response status code. + // These two values are combined with the name of the file with the request data. The request + // data is read in later, from a different directory, when executing the test. + private static Stream getTestFiles(String endsWith) throws IOException { + File responseDir = new File("src/test/mock-data/response"); + Stream.Builder streamBuilder = Stream.builder(); + try (DirectoryStream paths = Files.newDirectoryStream(responseDir.toPath())) { + for (Path p : paths) { + if (p.toString().endsWith(endsWith)) { + var responseBodyStream = new FileInputStream(p.toFile()); + var responseStr = IOUtils.toString(responseBodyStream, StandardCharsets.UTF_8); + responseBodyStream.close(); + + int statusCode = HTTP_OK; + var statusFilename = p.toString().replace(".json", ".status"); + File statusFile = new File(statusFilename); + if (statusFile.exists()) { + var statusStr = FileUtils.readFileToString(statusFile, StandardCharsets.UTF_8).trim(); + statusCode = Integer.parseInt(statusStr); + } + + streamBuilder.add(Arguments.of(p.getFileName().toString(), responseStr, statusCode)); + } } - mockServer.when(HttpRequest.request() - .withPath("/info")) - .respond(HttpResponse.response() - .withStatusCode(200) - .withHeader("Content-Type", "application/json") - .withHeader("X-RosetteAPI-Concurrency", "5") - .withBody(INFO_REPONSE, StandardCharsets.UTF_8)); - - api = new HttpRosetteAPI.Builder() - .key("my-key-123") - .url(mockServiceUrl) - .build(); } + return streamBuilder.build(); } - @Test - public void testMatchName() throws IOException { - if (!(testFilename.endsWith("-matched-name.json"))) { - return; - } - NameSimilarityRequest request = readValueNameMatcher(); + private static Stream testMatchNameParameters() throws IOException { + return getTestFiles("-name-similarity.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testMatchNameParameters") + void testMatchName(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + NameSimilarityRequest request = readValueNameMatcher(testFilename); try { - NameSimilarityResponse response = api.perform(AbstractRosetteAPI.NAME_SIMILARITY_SERVICE_PATH, request, NameSimilarityResponse.class); - verifyNameMatcher(response); + NameSimilarityResponse response = api.perform(AbstractRosetteAPI.NAME_SIMILARITY_SERVICE_PATH, request, + NameSimilarityResponse.class); + verifyNameMatcher(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private void verifyNameMatcher(NameSimilarityResponse response) throws IOException { + private void verifyNameMatcher(NameSimilarityResponse response, String responseStr) throws IOException { NameSimilarityResponse goldResponse = mapper.readValue(responseStr, NameSimilarityResponse.class); assertEquals(goldResponse.getScore(), response.getScore(), 0.0); } - private NameSimilarityRequest readValueNameMatcher() throws IOException { + private NameSimilarityRequest readValueNameMatcher(String testFilename) throws IOException { File input = new File("src/test/mock-data/request", testFilename); return mapper.readValue(input, NameSimilarityRequest.class); } - @Test - public void testTranslateName() throws IOException { - if (!(testFilename.endsWith("-translated-name.json"))) { - return; + private static Stream testMatchRecordParameters() throws IOException { + return getTestFiles("-record-similarity.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testMatchRecordParameters") + void testMatchRecord(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + RecordSimilarityRequest request = readValueRecordMatcher(testFilename); + try { + RecordSimilarityResponse response = api.perform(AbstractRosetteAPI.RECORD_SIMILARITY_SERVICE_PATH, request, + RecordSimilarityResponse.class); + verifyRecordMatcher(response, responseStr); + } catch (HttpRosetteAPIException e) { + verifyException(e, responseStr); + } + } + + private static Stream testMatchRecordMissingFieldParameters() throws IOException { + return getTestFiles("-record-similarity-missing-field.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testMatchRecordMissingFieldParameters") + void testMatchRecordMissingField(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + readValueRecordMatcher(testFilename); + assertEquals("{\"results\":[{\"score\":0.0,\"left\":{\"dob2\":\"1993/04/16\"," + + "\"dob\":\"1993-04-16\",\"primaryName\":{\"data\":\"Ethan R\",\"language\":\"eng\"," + + "\"entityType\":\"PERSON\"},\"addr\":\"123 Roadlane Ave\"},\"right\":{\"dob\":\"1993-04-16\"," + + "\"primaryName\":\"Seth R\"},\"error\":\"Field 'primaryName' not found in field mapping\"}," + + "{\"score\":0.0,\"left\":{\"dob\":\"1993-04-16\",\"primaryName\":\"Evan R\"}," + + "\"right\":{\"dob2\":\"1993/04/16\",\"dob\":\"1993-04-16\",\"primaryName\":\"Ivan R\"," + + "\"addr\":\"123 Roadlane Ave\"},\"error\":\"Field 'primaryName' not found in field mapping\"}]}", + responseStr); + } + + private static Stream testMatchRecordNullFieldParameters() throws IOException { + return getTestFiles("-record-similarity-null-field.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testMatchRecordNullFieldParameters") + void testMatchRecordNullField(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + + try { + readValueRecordMatcher(testFilename); + fail("Did not throw exception for a field with null type"); + } catch (IllegalArgumentException e) { + assertEquals("Unspecified field type for: primaryName", e.getMessage()); + } + } + + private void verifyRecordMatcher(RecordSimilarityResponse response, String responseStr) throws IOException { + RecordSimilarityResponse goldResponse = mapper.readValue(responseStr, RecordSimilarityResponse.class); + assertEquals(goldResponse.getResults(), response.getResults()); + } + + private RecordSimilarityRequest readValueRecordMatcher(String testFilename) throws IOException { + File input = new File("src/test/mock-data/request", testFilename); + return mapper.readValue(input, RecordSimilarityRequest.class); + } + + private static Stream testMatchAddressParameters() throws IOException { + return getTestFiles("-address-similarity.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testMatchAddressParameters") + void testMatchAddress(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + AddressSimilarityRequest request = readValueAddressMatcher(testFilename); + try { + AddressSimilarityResponse response = api.perform(AbstractRosetteAPI.ADDRESS_SIMILARITY_SERVICE_PATH, + request, AddressSimilarityResponse.class); + verifyAddressMatcher(response, responseStr); + } catch (HttpRosetteAPIException e) { + verifyException(e, responseStr); + } + } + + private void verifyAddressMatcher(AddressSimilarityResponse response, String responseStr) throws IOException { + AddressSimilarityResponse goldResponse = mapper.readValue(responseStr, AddressSimilarityResponse.class); + assertEquals(goldResponse.getScore(), response.getScore(), 0.0); + } + + private AddressSimilarityRequest readValueAddressMatcher(String testFilename) throws IOException { + File input = new File("src/test/mock-data/request", testFilename); + return mapper.readValue(input, AddressSimilarityRequest.class); + } + + private static Stream testTranslateNameParameters() throws IOException { + return getTestFiles("-name-translation.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testTranslateNameParameters") + void testTranslateName(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + NameTranslationRequest request = readValueNameTranslation(testFilename); + try { + NameTranslationResponse response = api.perform(AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH, request, + NameTranslationResponse.class); + verifyNameTranslation(response, responseStr); + } catch (HttpRosetteAPIException e) { + verifyException(e, responseStr); } - NameTranslationRequest request = readValueNameTranslation(); + } + + private static Stream testMultiTranslateNameParameters() throws IOException { + return getTestFiles("-multi-name-translation.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testMultiTranslateNameParameters") + void testMultiTranslateName(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + NameTranslationRequest request = readValueNameTranslation(testFilename); try { - NameTranslationResponse response = api.perform(AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH, request, NameTranslationResponse.class); - verifyNameTranslation(response); + NameTranslationResponse response = api.perform(AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH, request, + NameTranslationResponse.class); + verifyMultiNameTranslations(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private void verifyNameTranslation(NameTranslationResponse response) throws IOException { + private void verifyNameTranslation(NameTranslationResponse response, String responseStr) throws IOException { NameTranslationResponse goldResponse = mapper.readValue(responseStr, NameTranslationResponse.class); assertEquals(goldResponse.getTranslation(), response.getTranslation()); } - private NameTranslationRequest readValueNameTranslation() throws IOException { + private void verifyMultiNameTranslations(NameTranslationResponse response, String responseStr) throws IOException { + NameTranslationResponse goldResponse = mapper.readValue(responseStr, NameTranslationResponse.class); + assertEquals(goldResponse.getTranslations(), response.getTranslations()); + } + + private NameTranslationRequest readValueNameTranslation(String testFilename) throws IOException { File input = new File("src/test/mock-data/request", testFilename); return mapper.readValue(input, NameTranslationRequest.class); } - private void verifyLanguage(LanguageResponse response) throws IOException { + private void verifyLanguage(LanguageResponse response, String responseStr) throws IOException { LanguageResponse goldResponse = mapper.readValue(responseStr, LanguageResponse.class); assertEquals(goldResponse.getLanguageDetections().size(), response.getLanguageDetections().size()); } - @Test - public void testGetLanguageDoc() throws IOException { - if (!(testFilename.endsWith("-language.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetLanguageDocParameters() throws IOException { + return getTestFiles("-doc-language.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetLanguageDocParameters") + void testGetLanguageDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - LanguageResponse response = api.perform(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, request, LanguageResponse.class); - verifyLanguage(response); + LanguageResponse response = api.perform(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, request, + LanguageResponse.class); + verifyLanguage(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testGetLanguageURL() throws IOException { - if (!(testFilename.endsWith("-language.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetLanguageURLParameters() throws IOException { + return getTestFiles("-url-language.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetLanguageURLParameters") + void testGetLanguageURL(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - LanguageResponse response = api.perform(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, request, LanguageResponse.class); - verifyLanguage(response); + LanguageResponse response = api.perform(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, request, + LanguageResponse.class); + verifyLanguage(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testGetMorphologyDoc() throws IOException { - if (!(testFilename.endsWith("-morphology_complete.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetMorphologyDocParameters() throws IOException { + return getTestFiles("-doc-morphology_complete.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetMorphologyDocParameters") + void testGetMorphologyDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - MorphologyResponse response = api.perform(AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPLETE, request, MorphologyResponse.class); - verifyMorphology(response); + MorphologyResponse response = api.perform(AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + + MorphologicalFeature.COMPLETE, request, MorphologyResponse.class); + verifyMorphology(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private void verifyMorphology(MorphologyResponse response) throws IOException { + private void verifyMorphology(MorphologyResponse response, String responseStr) throws IOException { MorphologyResponse goldResponse = mapper.readValue(responseStr, MorphologyResponse.class); assertEquals(response.getPosTags().size(), goldResponse.getPosTags().size()); } - @Test - public void testGetMorphologyURL() throws IOException { - if (!(testFilename.endsWith("-morphology_complete.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetMorphologyURLParameters() throws IOException { + return getTestFiles("-url-morphology_complete.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetMorphologyURLParameters") + void testGetMorphologyURL(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - MorphologyResponse response = api.perform(AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPLETE, request, MorphologyResponse.class); - verifyMorphology(response); + MorphologyResponse response = api.perform(AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + + MorphologicalFeature.COMPLETE, request, MorphologyResponse.class); + verifyMorphology(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testGetEntityDoc() throws IOException { - if (!(testFilename.endsWith("-entities.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetEntityDocParameters() throws IOException { + return getTestFiles("-doc-entities.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetEntityDocParameters") + void testGetEntityDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); - verifyEntity(response); + EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, + EntitiesResponse.class); + verifyEntity(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testGetEntityLinked() throws IOException { - if (!(testFilename.endsWith("-entities_linked.json"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetEntityLinkedParameters() throws IOException { + return getTestFiles("-entities_linked.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetEntityLinkedParameters") + void testGetEntityLinked(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); - verifyEntity(response); + EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, + EntitiesResponse.class); + verifyEntity(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testIgnoredUnknownField() throws IOException { - if ("unknown-field-entities.json".equals(testFilename)) { - DocumentRequest request = readValue(DocumentRequest.class); + + private static Stream testGetEntityPermIdParameters() throws IOException { + return getTestFiles("-entities_permid.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetEntityPermIdParameters") + void testGetEntityPermId(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + if (testFilename.endsWith("-entities_permid.json")) { + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); - verifyEntity(response); + EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, + EntitiesResponse.class); + verifyEntity(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } } - @Test - public void testNonIgnoredUnknownField() throws IOException { - if ("unknown-field-entities.json".equals(testFilename)) { - DocumentRequest request = readValue(DocumentRequest.class); - HttpRosetteAPI tmpApi = new HttpRosetteAPI.Builder() - .key("my-key-123") - .url(mockServiceUrl) - .onlyAcceptKnownFields(true) - .build(); - try { - tmpApi.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); - } catch (RosetteRuntimeException e) { - if (e.getCause() instanceof UnrecognizedPropertyException) { - return; - } + private static Stream testIgnoredUnknownFieldParameters() throws IOException { + return getTestFiles("unknown-field-entities.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testIgnoredUnknownFieldParameters") + void testIgnoredUnknownField(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); + try { + EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, + EntitiesResponse.class); + verifyEntity(response, responseStr); + } catch (HttpRosetteAPIException e) { + verifyException(e, responseStr); + } + } + + private static Stream testNonIgnoredUnknownFieldParameters() throws IOException { + return getTestFiles("unknown-field-entities.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testNonIgnoredUnknownFieldParameters") + void testNonIgnoredUnknownField(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); + + try (HttpRosetteAPI tmpApi = new HttpRosetteAPI.Builder() + .key("my-key-123") + .url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) + .onlyAcceptKnownFields(true) + .build()) { + tmpApi.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); + } catch (RosetteRuntimeException e) { + if (e.getCause() instanceof UnrecognizedPropertyException) { + return; } - fail("Unknown field is ignored when it shouldn't be "); } + fail("Unknown field is ignored when it shouldn't be "); } - private void verifyEntity(EntitiesResponse response) throws IOException { + private void verifyEntity(EntitiesResponse response, String responseStr) throws IOException { EntitiesResponse goldResponse = mapper.readValue(responseStr, EntitiesResponse.class); assertEquals(goldResponse.getEntities(), response.getEntities()); } - @Test - public void testGetEntityURL() throws IOException { - if (!(testFilename.endsWith("-entities.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetEntityURLParameters() throws IOException { + return getTestFiles("-url-entities.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetEntityURLParameters") + void testGetEntityURL(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); - verifyEntity(response); + EntitiesResponse response = api.perform(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, request, + EntitiesResponse.class); + verifyEntity(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testGetCategories() throws IOException { - if (!(testFilename.endsWith("-categories.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetCategoriesDocParameters() throws IOException { + return getTestFiles("-doc-categories.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetCategoriesDocParameters") + void testGetCategoriesDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - CategoriesResponse response = api.perform(AbstractRosetteAPI.CATEGORIES_SERVICE_PATH, request, CategoriesResponse.class); - verifyCategory(response); + CategoriesResponse response = api.perform(AbstractRosetteAPI.CATEGORIES_SERVICE_PATH, request, + CategoriesResponse.class); + verifyCategory(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - - private void verifyCategory(CategoriesResponse response) throws IOException { + private void verifyCategory(CategoriesResponse response, String responseStr) throws IOException { CategoriesResponse goldResponse = mapper.readValue(responseStr, CategoriesResponse.class); assertEquals(response.getCategories().size(), goldResponse.getCategories().size()); } - @Test - public void testGetCategoriesURL() throws IOException { - if (!(testFilename.endsWith("-categories.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetCategoriesURLParameters() throws IOException { + return getTestFiles("-url-categories.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetCategoriesURLParameters") + void testGetCategoriesURL(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - CategoriesResponse response = api.perform(AbstractRosetteAPI.CATEGORIES_SERVICE_PATH, request, CategoriesResponse.class); - verifyCategory(response); + CategoriesResponse response = api.perform(AbstractRosetteAPI.CATEGORIES_SERVICE_PATH, request, + CategoriesResponse.class); + verifyCategory(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - @Test - public void testGetSyntaxDependencies() throws IOException { - if (!(testFilename.endsWith("-syntax_dependencies.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetSyntaxDependenciesDocParameters() throws IOException { + return getTestFiles("-doc-syntax_dependencies.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetSyntaxDependenciesDocParameters") + void testGetSyntaxDependenciesDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - SyntaxDependenciesResponse response = api.perform(AbstractRosetteAPI.SYNTAX_DEPENDENCIES_SERVICE_PATH, request, SyntaxDependenciesResponse.class); - verifySyntaxDependency(response); + SyntaxDependenciesResponse response = api.perform(AbstractRosetteAPI.SYNTAX_DEPENDENCIES_SERVICE_PATH, + request, SyntaxDependenciesResponse.class); + verifySyntaxDependency(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - - private void verifySyntaxDependency(SyntaxDependenciesResponse response) throws IOException { + private void verifySyntaxDependency(SyntaxDependenciesResponse response, String responseStr) throws IOException { SyntaxDependenciesResponse goldResponse = mapper.readValue(responseStr, SyntaxDependenciesResponse.class); assertEquals(response.getSentences().size(), goldResponse.getSentences().size()); } - @Test - public void testGetSyntaxDependenciesURL() throws IOException { - if (!(testFilename.endsWith("-syntax_dependencies.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetSimilarTermsParameters() throws IOException { + return getTestFiles("-similar_terms.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetSimilarTermsParameters") + void testGetSimilarTerms(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - SyntaxDependenciesResponse response = api.perform(AbstractRosetteAPI.SYNTAX_DEPENDENCIES_SERVICE_PATH, request, SyntaxDependenciesResponse.class); - verifySyntaxDependency(response); + SimilarTermsResponse response = api.perform(AbstractRosetteAPI.SIMILAR_TERMS_SERVICE_PATH, request, + SimilarTermsResponse.class); + verifySimilarTerms(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - // THERE ARE NO REL FILENAMES! - @Test - public void testGetRelationships() throws IOException { - if (!(testFilename.endsWith("-relationships.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private void verifySimilarTerms(SimilarTermsResponse response, String responseStr) throws IOException { + SimilarTermsResponse goldResponse = mapper.readValue(responseStr, SimilarTermsResponse.class); + assertEquals(response.getSimilarTerms().size(), goldResponse.getSimilarTerms().size()); + } + + private static Stream testGetRelationshipsDocParameters() throws IOException { + return getTestFiles("-doc-relationships.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetRelationshipsDocParameters") + void testGetRelationshipsDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - RelationshipsResponse response = api.perform(AbstractRosetteAPI.RELATIONSHIPS_SERVICE_PATH, request, RelationshipsResponse.class); - verifyRelationships(response); + RelationshipsResponse response = api.perform(AbstractRosetteAPI.RELATIONSHIPS_SERVICE_PATH, request, + RelationshipsResponse.class); + verifyRelationships(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private void verifyRelationships(RelationshipsResponse response) throws IOException { + private void verifyRelationships(RelationshipsResponse response, String responseStr) throws IOException { RelationshipsResponse goldResponse = mapper.readValue(responseStr, RelationshipsResponse.class); assertEquals(response.getRelationships().size(), goldResponse.getRelationships().size()); } - @Test - public void testGetRelationshipsURL() throws IOException { - if (!(testFilename.endsWith("-relationships.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); - try { - RelationshipsResponse response = api.perform(AbstractRosetteAPI.RELATIONSHIPS_SERVICE_PATH, request, RelationshipsResponse.class); - verifyRelationships(response); - } catch (HttpRosetteAPIException e) { - verifyException(e); - } + private static Stream testGetSentimentDocParameters() throws IOException { + return getTestFiles("-doc-sentiment.json"); } - @Test - public void testGetSentiment() throws IOException { - if (!(testFilename.endsWith("-sentiment.json") && testFilename.contains("-doc-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetSentimentDocParameters") + void testGetSentimentDoc(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - SentimentResponse response = api.perform(AbstractRosetteAPI.SENTENCES_SERVICE_PATH, request, SentimentResponse.class); - verifySentiment(response); + SentimentResponse response = api.perform(AbstractRosetteAPI.SENTENCES_SERVICE_PATH, request, + SentimentResponse.class); + verifySentiment(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private void verifySentiment(SentimentResponse response) throws IOException { + private void verifySentiment(SentimentResponse response, String responseStr) throws IOException { SentimentResponse goldResponse = mapper.readValue(responseStr, SentimentResponse.class); // this is minimal. assertNotNull(response.getEntities()); assertEquals(response.getEntities().size(), goldResponse.getEntities().size()); } - @Test - public void testGetSentimentURL() throws IOException { - if (!(testFilename.endsWith("-sentiment.json") && testFilename.contains("-url-"))) { - return; - } - DocumentRequest request = readValue(DocumentRequest.class); + private static Stream testGetSentimentURLParameters() throws IOException { + return getTestFiles("-url-sentiment.json"); + } + + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testGetSentimentURLParameters") + void testGetSentimentURL(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + DocumentRequest request = readValue(DocumentRequest.class, testFilename); try { - SentimentResponse response = api.perform(AbstractRosetteAPI.SENTENCES_SERVICE_PATH, request, SentimentResponse.class); - verifySentiment(response); + SentimentResponse response = api.perform(AbstractRosetteAPI.SENTENCES_SERVICE_PATH, request, + SentimentResponse.class); + verifySentiment(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private T readValue(Class clazz) throws IOException { - File input = new File("src/test/mock-data/request", testFilename); - return mapper.readValue(input, clazz); - } - - private void verifyException(HttpRosetteAPIException e) throws IOException { - ErrorResponse goldResponse = mapper.readValue(responseStr, ErrorResponse.class); - assertEquals(goldResponse.getCode(), e.getErrorResponse().getCode()); + private static Stream testNameDeduplicationParameters() throws IOException { + return getTestFiles("-name-deduplication.json"); } - @Test - public void testNameDeduplication() throws IOException { - if (!(testFilename.endsWith("-name-deduplication.json"))) { - return; - } - NameDeduplicationRequest request = readValueNameDeduplication(); + @ParameterizedTest(name = "testFilename: {0}; statusCode: {2}") + @MethodSource("testNameDeduplicationParameters") + void testNameDeduplication(String testFilename, String responseStr, int statusCode) throws IOException { + setStatusCodeResponse(responseStr, statusCode); + NameDeduplicationRequest request = readValueNameDeduplication(testFilename); try { NameDeduplicationResponse response = api.perform(AbstractRosetteAPI.NAME_DEDUPLICATION_SERVICE_PATH, request, NameDeduplicationResponse.class); - verifyNameDeduplication(response); + verifyNameDeduplication(response, responseStr); } catch (HttpRosetteAPIException e) { - verifyException(e); + verifyException(e, responseStr); } } - private void verifyNameDeduplication(NameDeduplicationResponse response) throws IOException { + private void verifyNameDeduplication(NameDeduplicationResponse response, String responseStr) throws IOException { NameDeduplicationResponse goldResponse = mapper.readValue(responseStr, NameDeduplicationResponse.class); assertEquals(goldResponse.getResults(), response.getResults()); } - private NameDeduplicationRequest readValueNameDeduplication() throws IOException { + private NameDeduplicationRequest readValueNameDeduplication(String testFilename) throws IOException { File input = new File("src/test/mock-data/request", testFilename); return mapper.readValue(input, NameDeduplicationRequest.class); } diff --git a/api/src/test/java/com/basistech/rosette/api/RosetteRequestTest.java b/api/src/test/java/com/basistech/rosette/api/RosetteRequestTest.java new file mode 100644 index 000000000..f57027b10 --- /dev/null +++ b/api/src/test/java/com/basistech/rosette/api/RosetteRequestTest.java @@ -0,0 +1,190 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.basistech.rosette.api; + +import com.basistech.rosette.api.common.AbstractRosetteAPI; +import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.EntitiesOptions; +import com.basistech.rosette.apimodel.EntitiesResponse; +import com.basistech.rosette.apimodel.ErrorResponse; +import com.basistech.rosette.apimodel.LanguageOptions; +import com.basistech.rosette.apimodel.LanguageResponse; +import com.basistech.rosette.apimodel.Response; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockserver.client.MockServerClient; +import org.mockserver.junit.jupiter.MockServerExtension; +import org.mockserver.matchers.Times; +import org.mockserver.model.HttpRequest; +import org.mockserver.model.HttpResponse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(MockServerExtension.class) +class RosetteRequestTest { + private MockServerClient mockServer; + private HttpRosetteAPI api; + + @BeforeEach + void setup(MockServerClient mockServer) { + this.mockServer = mockServer; + } + + private void setupResponse(String requestPath, String responseString, int statusCode, int delayMillis, int requestTimes) { + this.mockServer.when(HttpRequest.request().withPath(requestPath), Times.exactly(requestTimes)) + .respond(HttpResponse.response() + .withHeader("Content-Type", "application/json") + .withHeader("X-BabelStreetAPI-Concurrency", "5") + .withStatusCode(statusCode) + .withBody(responseString) + .withDelay(TimeUnit.MILLISECONDS, delayMillis)); + } + + + @Test + void successfulRequest() throws ExecutionException, InterruptedException { + //Api client setup + this.api = new HttpRosetteAPI.Builder().url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())).build(); + + //response setup + String entitiesResponse = "{\"entities\" : [ { \"type\" : \"ORGANIZATION\", \"mention\" : \"Securities and Exchange Commission\", \"normalized\" : \"U.S. Securities and Exchange Commission\", \"count\" : 1, \"mentionOffsets\" : [ { \"startOffset\" : 4, \"endOffset\" : 38 } ], \"entityId\" : \"Q953944\", \"confidence\" : 0.39934742, \"linkingConfidence\" : 0.67404154 } ] }"; + setupResponse("/rest/v1/entities", entitiesResponse, 200, 0, 1); + + //request setup + String entitiesTextData = "The Securities and Exchange Commission today announced the leadership of the agency’s trial unit."; + DocumentRequest entitiesRequestData = DocumentRequest.builder() + .content(entitiesTextData) + .build(); + RosetteRequest entitiesRequest = this.api.createRosetteRequest(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, entitiesRequestData, EntitiesResponse.class); + + //testing the request + ExecutorService threadPool = Executors.newFixedThreadPool(1); + Future response = threadPool.submit(entitiesRequest); + assertInstanceOf(EntitiesResponse.class, response.get()); + assertEquals(response.get(), entitiesRequest.getResponse()); + threadPool.shutdownNow(); + } + + + @Test + void errorResponse() throws ExecutionException, InterruptedException { + //Api client setup + this.api = new HttpRosetteAPI.Builder().url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())).build(); + + //response setup + String entitiesResponse = "{ \"code\" : \"badRequestFormat\", \"message\" : \"no content provided; must be one of an attachment, an inline \\\"content\\\" field, or an external \\\"contentUri\\\"\" }"; + setupResponse("/rest/v1/entities", entitiesResponse, 400, 0, 1); + + //request setup + DocumentRequest entitiesRequestData = DocumentRequest.builder() + .build(); + RosetteRequest entitiesRequest = this.api.createRosetteRequest(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, entitiesRequestData, EntitiesResponse.class); + + //testing the request + ExecutorService threadPool = Executors.newFixedThreadPool(1); + Future response = threadPool.submit(entitiesRequest); + assertInstanceOf(ErrorResponse.class, response.get()); + assertEquals(response.get(), entitiesRequest.getResponse()); + threadPool.shutdownNow(); + } + + @Test + void testTiming() throws ExecutionException, InterruptedException { + int delay = 100; + //api setup + this.api = new HttpRosetteAPI.Builder().url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) + .connectionConcurrency(1).build(); + + //responses setup + int entitiesRespCount = 10; + int languageRespCount = 4; + assertEquals(0, entitiesRespCount % 2); + assertEquals(0, entitiesRespCount % 2); + String entitiesResponse = "{\"entities\" : [ { \"type\" : \"ORGANIZATION\", \"mention\" : \"Securities and Exchange Commission\", \"normalized\" : \"U.S. Securities and Exchange Commission\", \"count\" : 1, \"mentionOffsets\" : [ { \"startOffset\" : 4, \"endOffset\" : 38 } ], \"entityId\" : \"Q953944\", \"confidence\" : 0.39934742, \"linkingConfidence\" : 0.67404154 } ] }"; + setupResponse("/rest/v1/entities", entitiesResponse, 200, delay, entitiesRespCount); + String languageResponse = " {\"code\" : \"badRequestFormat\", \"message\" : \"no content provided; must be one of an attachment, an inline \\\"content\\\" field, or an external \\\"contentUri\\\"\" }"; + setupResponse("/rest/v1/language", languageResponse, 400, delay, languageRespCount); + + //requests setup + String entitiesTextData = "The Securities and Exchange Commission today announced the leadership of the agency’s trial unit."; + DocumentRequest entitiesRequestData = DocumentRequest.builder() + .content(entitiesTextData) + .build(); + DocumentRequest languageRequestData = DocumentRequest.builder().build(); + List requests = new ArrayList<>(); + for (int i = 0; i < entitiesRespCount / 2; i++) { + requests.add(this.api.createRosetteRequest(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, entitiesRequestData, EntitiesResponse.class)); + } + for (int i = 0; i < languageRespCount / 2; i++) { + requests.add(this.api.createRosetteRequest(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, languageRequestData, LanguageResponse.class)); + } + + //run requests + ExecutorService threadPool = Executors.newFixedThreadPool(7); + Date d1 = new Date(); + List> responses = threadPool.invokeAll(requests); + for (int i = 0; i < responses.size(); i++) { + responses.get(i).get(); + } + Date d2 = new Date(); + + assertTrue(d2.getTime() - d1.getTime() > delay * requests.size()); // at least as long as the delay in the request + + //run requests concurrently + int concurrency = 3; + this.api = new HttpRosetteAPI.Builder().url(String.format("http://localhost:%d/rest/v1", mockServer.getPort())) + .connectionConcurrency(3).build(); + + requests = new ArrayList<>(); + for (int i = 0; i < entitiesRespCount / 2; i++) { + requests.add(this.api.createRosetteRequest(AbstractRosetteAPI.ENTITIES_SERVICE_PATH, entitiesRequestData, EntitiesResponse.class)); + } + for (int i = 0; i < entitiesRespCount / 2; i++) { + requests.add(this.api.createRosetteRequest(AbstractRosetteAPI.LANGUAGE_SERVICE_PATH, languageRequestData, LanguageResponse.class)); + } + + + d1 = new Date(); + responses = threadPool.invokeAll(requests); + for (int i = 0; i < responses.size(); i++) { + responses.get(i).get(); + } + d2 = new Date(); + + assertTrue(d2.getTime() - d1.getTime() < delay * requests.size()); // less than serial requests + assertTrue(d2.getTime() - d1.getTime() > requests.size() / concurrency * delay); // running faster than this would suggest it exceeds the maximum concurrency + } + + @AfterEach + void after() throws IOException { + this.api.close(); + } + +} \ No newline at end of file diff --git a/api/src/test/mock-data/mockgen.py b/api/src/test/mock-data/mockgen.py index b9bad89d7..9cf79248c 100755 --- a/api/src/test/mock-data/mockgen.py +++ b/api/src/test/mock-data/mockgen.py @@ -50,7 +50,7 @@ def capture(req, endpoints, filename_prefix): headers = {"Content-Type": "application/json"} if args.api_key: - headers['X-RosetteAPI-Key'] = args.api_key + headers['X-BabelStreetAPI-Key'] = args.api_key # prep & clean up for folder in ["request", "response"]: diff --git a/api/src/test/mock-data/request/eng-doc-entities_permid.json b/api/src/test/mock-data/request/eng-doc-entities_permid.json new file mode 100644 index 000000000..30babf63d --- /dev/null +++ b/api/src/test/mock-data/request/eng-doc-entities_permid.json @@ -0,0 +1,4 @@ +{ + "content": "Toyota and Microsoft are large cap companies.", + "language": "eng" +} diff --git a/api/src/test/mock-data/request/eng-doc-relationships.json b/api/src/test/mock-data/request/eng-doc-relationships.json new file mode 100644 index 000000000..a27da8854 --- /dev/null +++ b/api/src/test/mock-data/request/eng-doc-relationships.json @@ -0,0 +1,6 @@ +{ + "content": "FLIR Systems is headquartered in Oregon and produces thermal imaging, night vision, and infrared cameras and sensor systems. According to the SEC’s order instituting a settled administrative proceeding, FLIR entered into a multi-million dollar contract to provide thermal binoculars to the Saudi government in November 2008. Timms and Ramahi were the primary sales employees responsible for the contract, and also were involved in negotiations to sell FLIR’s security cameras to the same government officials. At the time, Timms was the head of FLIR’s Middle East office in Dubai.", + "language": "eng" +} + + diff --git a/api/src/test/mock-data/request/eng-doc-similar_terms.json b/api/src/test/mock-data/request/eng-doc-similar_terms.json new file mode 100644 index 000000000..5c93e0b0c --- /dev/null +++ b/api/src/test/mock-data/request/eng-doc-similar_terms.json @@ -0,0 +1,5 @@ +{ + "content": "spy", + "resultLanguages": ["spa", "deu", "jpn"], + "language": "eng" +} \ No newline at end of file diff --git a/api/src/test/mock-data/request/eng-doc-syntax_dependencies.json b/api/src/test/mock-data/request/eng-doc-syntax_dependencies.json new file mode 100644 index 000000000..0a9683328 --- /dev/null +++ b/api/src/test/mock-data/request/eng-doc-syntax_dependencies.json @@ -0,0 +1,4 @@ +{ + "content": "Yoshinori Ohsumi, a Japanese cell biologist, was awarded the Nobel Prize in Physiology or Medicine on Monday.", + "language": "eng" +} \ No newline at end of file diff --git a/api/src/test/mock-data/request/rni-1-address-similarity.json b/api/src/test/mock-data/request/rni-1-address-similarity.json new file mode 100644 index 000000000..9e070798a --- /dev/null +++ b/api/src/test/mock-data/request/rni-1-address-similarity.json @@ -0,0 +1,16 @@ +{ + "address1": { + "houseNumber" : "1600", + "road" : "Pennsylvania Ave NW", + "city" : "Washington", + "state" : "DC", + "postCode" : "20500" + }, + "address2": { + "houseNumber" : "160", + "road" : "Pennsilvana Ave", + "city" : "Washington", + "state" : "D.C.", + "postCode" : "20500" + } +} \ No newline at end of file diff --git a/api/src/test/mock-data/request/rni-1-record-similarity-missing-field.json b/api/src/test/mock-data/request/rni-1-record-similarity-missing-field.json new file mode 100644 index 000000000..dfe1dfa3c --- /dev/null +++ b/api/src/test/mock-data/request/rni-1-record-similarity-missing-field.json @@ -0,0 +1,53 @@ +{ + "fields": { + "homeAddress": { + "type": "rni_address", + "weight": 0.5 + }, + "dob": { + "type": "rni_date", + "weight": 0.2 + }, + "dob2": { + "type": "rni_date", + "weight": 0.1 + }, + "addr": { + "type": "rni_address", + "weight": 0.5 + } + }, + "properties": { + "threshold": 0.7 + }, + "records": { + "left": [ + { + "primaryName": { + "data": "Ethan R", + "language": "eng", + "entityType": "PERSON" + }, + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + }, + { + "primaryName": "Evan R", + "dob": "1993-04-16" + } + ], + "right": [ + { + "primaryName": "Seth R", + "dob": "1993-04-16" + }, + { + "primaryName": "Ivan R", + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + } + ] + } +} \ No newline at end of file diff --git a/api/src/test/mock-data/request/rni-1-record-similarity-null-field.json b/api/src/test/mock-data/request/rni-1-record-similarity-null-field.json new file mode 100644 index 000000000..5802f2f91 --- /dev/null +++ b/api/src/test/mock-data/request/rni-1-record-similarity-null-field.json @@ -0,0 +1,53 @@ +{ + "fields": { + "primaryName": { + "type": null, + "weight": 0.5 + }, + "dob": { + "type": "rni_date", + "weight": 0.2 + }, + "dob2": { + "type": "rni_date", + "weight": 0.1 + }, + "addr": { + "type": "rni_address", + "weight": 0.5 + } + }, + "properties": { + "threshold": 0.7 + }, + "records": { + "left": [ + { + "primaryName": { + "data": "Ethan R", + "language": "eng", + "entityType": "PERSON" + }, + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + }, + { + "primaryName": "Evan R", + "dob": "1993-04-16" + } + ], + "right": [ + { + "primaryName": "Seth R", + "dob": "1993-04-16" + }, + { + "primaryName": "Ivan R", + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + } + ] + } +} \ No newline at end of file diff --git a/api/src/test/mock-data/request/rni-1-record-similarity.json b/api/src/test/mock-data/request/rni-1-record-similarity.json new file mode 100644 index 000000000..ff91c578f --- /dev/null +++ b/api/src/test/mock-data/request/rni-1-record-similarity.json @@ -0,0 +1,59 @@ +{ + "fields": { + "primaryName": { + "type": "rni_name", + "weight": 0.5 + }, + "dob": { + "type": "rni_date", + "weight": 0.2 + }, + "dob2": { + "type": "rni_date", + "weight": 0.1 + }, + "addr": { + "type": "rni_address", + "weight": 0.5 + } + }, + "properties": { + "threshold": 0.7 + }, + "records": { + "left": [ + { + "primaryName": { + "text": "Ethan R", + "language": "eng", + "entityType": "PERSON" + }, + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + }, + { + "primaryName": { + "text": "Evan R" + }, + "dob": "1993-04-16" + } + ], + "right": [ + { + "primaryName": { + "text": "Seth R" + }, + "dob": "1993-04-16" + }, + { + "primaryName": { + "text": "Ivan R" + }, + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + } + ] + } +} diff --git a/api/src/test/mock-data/request/rnt-1-multi-name-translation.json b/api/src/test/mock-data/request/rnt-1-multi-name-translation.json new file mode 100644 index 000000000..4f17c3b1d --- /dev/null +++ b/api/src/test/mock-data/request/rnt-1-multi-name-translation.json @@ -0,0 +1,11 @@ +{ + "entityType": "PERSON", + "name": "معمر محمد أبو منيار القذاف", + "sourceLanguageOfOrigin": "ara", + "sourceLanguageOfUse": "ara", + "sourceScript": "Arab", + "targetLanguage": "eng", + "targetScheme": "IC", + "targetScript": "Latn", + "maximumResults": 10 +} diff --git a/api/src/test/mock-data/response/eng-doc-entities_permid.json b/api/src/test/mock-data/response/eng-doc-entities_permid.json new file mode 100644 index 000000000..1f5e718af --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-entities_permid.json @@ -0,0 +1,34 @@ +{ + "entities": [ + { + "type": "ORGANIZATION", + "mention": "Toyota", + "normalized": "Toyota", + "count": 1, + "mentionOffsets": [ + { + "startOffset": 0, + "endOffset": 6 + } + ], + "entityId": "Q53268", + "linkingConfidence": 0.45885878, + "permId": "4295876746" + }, + { + "type": "ORGANIZATION", + "mention": "Microsoft", + "normalized": "Microsoft", + "count": 1, + "mentionOffsets": [ + { + "startOffset": 11, + "endOffset": 20 + } + ], + "entityId": "Q2283", + "linkingConfidence": 0.76733641, + "permId": "4295907168" + } + ] +} diff --git a/api/src/test/mock-data/response/eng-doc-entities_permid.status b/api/src/test/mock-data/response/eng-doc-entities_permid.status new file mode 100644 index 000000000..08839f6bb --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-entities_permid.status @@ -0,0 +1 @@ +200 diff --git a/api/src/test/mock-data/response/eng-doc-relationships.json b/api/src/test/mock-data/response/eng-doc-relationships.json new file mode 100644 index 000000000..51ac462e7 --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-relationships.json @@ -0,0 +1,33 @@ +{ + "relationships": [ + { + "predicate": "Organization Headquarters", + "predicateId": "ORG-HEADQUARTERS", + "arg1": "FLIR Systems", + "arg1Id": "Q5426537", + "arg2": "Oregon", + "arg2Id": "Q824" + }, + { + "predicate": "Citizen of", + "predicateId": "CIT-OF", + "arg1": "Timms", + "arg1Id": "T5", + "arg2": "Dubai", + "arg2Id": "Q612", + "confidence": 0.89470345 + }, + { + "predicate": "Person Employee or Member of", + "predicateId": "PER-EMPLOYEE-MEMBER-OF", + "arg1": "Timms", + "arg2": "FLIR" + }, + { + "predicate": "Organization top employees", + "predicateId": "ORG-TOP-EMPLOYEES", + "arg1": "FLIR", + "arg2": "Timms" + } + ] +} diff --git a/api/src/test/mock-data/response/eng-doc-relationships.status b/api/src/test/mock-data/response/eng-doc-relationships.status new file mode 100644 index 000000000..ae4ee13c0 --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-relationships.status @@ -0,0 +1 @@ +200 \ No newline at end of file diff --git a/api/src/test/mock-data/response/eng-doc-similar_terms.json b/api/src/test/mock-data/response/eng-doc-similar_terms.json new file mode 100644 index 000000000..e22e42d84 --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-similar_terms.json @@ -0,0 +1,130 @@ +{ + "similarTerms": { + "deu": [ + { + "term": "Deckname", + "similarity": 0.51391315 + }, + { + "term": "GRU", + "similarity": 0.50809389 + }, + { + "term": "Spion", + "similarity": 0.50051737 + }, + { + "term": "KGB", + "similarity": 0.49981388 + }, + { + "term": "Informant", + "similarity": 0.48774603 + }, + { + "term": "Geheimagent", + "similarity": 0.48700801 + }, + { + "term": "Geheimdienst", + "similarity": 0.48512384 + }, + { + "term": "Spionin", + "similarity": 0.47224587 + }, + { + "term": "MI6", + "similarity": 0.46969846 + }, + { + "term": "Decknamen", + "similarity": 0.44730526 + } + ], + "jpn": [ + { + "term": "スパイ", + "similarity": 0.5544399 + }, + { + "term": "諜報", + "similarity": 0.46903181 + }, + { + "term": "MI6", + "similarity": 0.46344957 + }, + { + "term": "殺し屋", + "similarity": 0.41098994 + }, + { + "term": "正体", + "similarity": 0.40109193 + }, + { + "term": "プレデター", + "similarity": 0.39433435 + }, + { + "term": "レンズマン", + "similarity": 0.3918637 + }, + { + "term": "S.H.I.E.L.D.", + "similarity": 0.38338536 + }, + { + "term": "サーシャ", + "similarity": 0.37628397 + }, + { + "term": "黒幕", + "similarity": 0.37256041 + } + ], + "spa": [ + { + "term": "espía", + "similarity": 0.61295485 + }, + { + "term": "cia", + "similarity": 0.46201307 + }, + { + "term": "desertor", + "similarity": 0.42849663 + }, + { + "term": "cómplice", + "similarity": 0.36646274 + }, + { + "term": "subrepticiamente", + "similarity": 0.36629659 + }, + { + "term": "asesino", + "similarity": 0.36264464 + }, + { + "term": "misterioso", + "similarity": 0.35466132 + }, + { + "term": "fugitivo", + "similarity": 0.35033143 + }, + { + "term": "informante", + "similarity": 0.34707013 + }, + { + "term": "mercenario", + "similarity": 0.34658083 + } + ] + } +} \ No newline at end of file diff --git a/api/src/test/mock-data/response/eng-doc-similar_terms.status b/api/src/test/mock-data/response/eng-doc-similar_terms.status new file mode 100644 index 000000000..ae4ee13c0 --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-similar_terms.status @@ -0,0 +1 @@ +200 \ No newline at end of file diff --git a/api/src/test/mock-data/response/eng-doc-syntax_dependencies.json b/api/src/test/mock-data/response/eng-doc-syntax_dependencies.json new file mode 100644 index 000000000..e05e78965 --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-syntax_dependencies.json @@ -0,0 +1,132 @@ +{ + "sentences": [ + { + "startTokenIndex": 0, + "endTokenIndex": 19, + "dependencies": [ + { + "dependencyType": "name", + "governorTokenIndex": 1, + "dependentTokenIndex": 0 + }, + { + "dependencyType": "nsubjpass", + "governorTokenIndex": 9, + "dependentTokenIndex": 1 + }, + { + "dependencyType": "punct", + "governorTokenIndex": 1, + "dependentTokenIndex": 2 + }, + { + "dependencyType": "det", + "governorTokenIndex": 6, + "dependentTokenIndex": 3 + }, + { + "dependencyType": "amod", + "governorTokenIndex": 6, + "dependentTokenIndex": 4 + }, + { + "dependencyType": "compound", + "governorTokenIndex": 6, + "dependentTokenIndex": 5 + }, + { + "dependencyType": "appos", + "governorTokenIndex": 1, + "dependentTokenIndex": 6 + }, + { + "dependencyType": "punct", + "governorTokenIndex": 1, + "dependentTokenIndex": 7 + }, + { + "dependencyType": "auxpass", + "governorTokenIndex": 9, + "dependentTokenIndex": 8 + }, + { + "dependencyType": "root", + "governorTokenIndex": -1, + "dependentTokenIndex": 9 + }, + { + "dependencyType": "det", + "governorTokenIndex": 12, + "dependentTokenIndex": 10 + }, + { + "dependencyType": "compound", + "governorTokenIndex": 12, + "dependentTokenIndex": 11 + }, + { + "dependencyType": "dobj", + "governorTokenIndex": 9, + "dependentTokenIndex": 12 + }, + { + "dependencyType": "case", + "governorTokenIndex": 14, + "dependentTokenIndex": 13 + }, + { + "dependencyType": "nmod", + "governorTokenIndex": 12, + "dependentTokenIndex": 14 + }, + { + "dependencyType": "cc", + "governorTokenIndex": 14, + "dependentTokenIndex": 15 + }, + { + "dependencyType": "conj", + "governorTokenIndex": 14, + "dependentTokenIndex": 16 + }, + { + "dependencyType": "case", + "governorTokenIndex": 18, + "dependentTokenIndex": 17 + }, + { + "dependencyType": "nmod", + "governorTokenIndex": 9, + "dependentTokenIndex": 18 + }, + { + "dependencyType": "punct", + "governorTokenIndex": 9, + "dependentTokenIndex": 19 + } + ] + } + ], + "tokens": [ + "Yoshinori", + "Ohsumi", + ",", + "a", + "Japanese", + "cell", + "biologist", + ",", + "was", + "awarded", + "the", + "Nobel", + "Prize", + "in", + "Physiology", + "or", + "Medicine", + "on", + "Monday", + "." + ] +} diff --git a/api/src/test/mock-data/response/eng-doc-syntax_dependencies.status b/api/src/test/mock-data/response/eng-doc-syntax_dependencies.status new file mode 100644 index 000000000..ae4ee13c0 --- /dev/null +++ b/api/src/test/mock-data/response/eng-doc-syntax_dependencies.status @@ -0,0 +1 @@ +200 \ No newline at end of file diff --git a/api/src/test/mock-data/response/eng-url-entities.json b/api/src/test/mock-data/response/eng-url-entities.json index 143f2a63e..dc6458d64 100644 --- a/api/src/test/mock-data/response/eng-url-entities.json +++ b/api/src/test/mock-data/response/eng-url-entities.json @@ -20,8 +20,9 @@ "mention": "Washington", "normalized": "Washington", "type": "LOCATION", - "dbpediaType": "test1" - + "dbpediaTypes": [ + "test1" + ] } ] } diff --git a/api/src/test/mock-data/response/eng-url-entities_linked.json b/api/src/test/mock-data/response/eng-url-entities_linked.json index 6d0b88bf0..ec851ebcd 100644 --- a/api/src/test/mock-data/response/eng-url-entities_linked.json +++ b/api/src/test/mock-data/response/eng-url-entities_linked.json @@ -17,7 +17,11 @@ "entityId": "Q1088831", "indocChainId": 2, "mention": "Washington", - "dbpediaType": "test1" + "dbpediaTypes": [ + "test1", + "foo", + "bar" + ] } ] -} \ No newline at end of file +} diff --git a/api/src/test/mock-data/response/rni-1-address-similarity.json b/api/src/test/mock-data/response/rni-1-address-similarity.json new file mode 100644 index 000000000..5bcc39519 --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-address-similarity.json @@ -0,0 +1,3 @@ +{ + "score": 0.77 +} \ No newline at end of file diff --git a/api/src/test/mock-data/response/rni-1-address-similarity.status b/api/src/test/mock-data/response/rni-1-address-similarity.status new file mode 100644 index 000000000..ae4ee13c0 --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-address-similarity.status @@ -0,0 +1 @@ +200 \ No newline at end of file diff --git a/api/src/test/mock-data/response/rni-1-record-similarity-missing-field.json b/api/src/test/mock-data/response/rni-1-record-similarity-missing-field.json new file mode 100644 index 000000000..a96a999bf --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-record-similarity-missing-field.json @@ -0,0 +1 @@ +{"results":[{"score":0.0,"left":{"dob2":"1993/04/16","dob":"1993-04-16","primaryName":{"data":"Ethan R","language":"eng","entityType":"PERSON"},"addr":"123 Roadlane Ave"},"right":{"dob":"1993-04-16","primaryName":"Seth R"},"error":"Field 'primaryName' not found in field mapping"},{"score":0.0,"left":{"dob":"1993-04-16","primaryName":"Evan R"},"right":{"dob2":"1993/04/16","dob":"1993-04-16","primaryName":"Ivan R","addr":"123 Roadlane Ave"},"error":"Field 'primaryName' not found in field mapping"}]} \ No newline at end of file diff --git a/api/src/test/mock-data/response/rni-1-record-similarity-missing-field.status b/api/src/test/mock-data/response/rni-1-record-similarity-missing-field.status new file mode 100644 index 000000000..6b3ed8d68 --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-record-similarity-missing-field.status @@ -0,0 +1 @@ +400 \ No newline at end of file diff --git a/api/src/test/mock-data/response/rni-1-record-similarity-null-field.json b/api/src/test/mock-data/response/rni-1-record-similarity-null-field.json new file mode 100644 index 000000000..13a42c51e --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-record-similarity-null-field.json @@ -0,0 +1,5 @@ +{ + "code": "badRequestFormat", + "message": "Unspecified field type for: primaryName", + "stack": null +} \ No newline at end of file diff --git a/api/src/test/mock-data/response/rni-1-record-similarity-null-field.status b/api/src/test/mock-data/response/rni-1-record-similarity-null-field.status new file mode 100644 index 000000000..6b3ed8d68 --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-record-similarity-null-field.status @@ -0,0 +1 @@ +400 \ No newline at end of file diff --git a/api/src/test/mock-data/response/rni-1-record-similarity.json b/api/src/test/mock-data/response/rni-1-record-similarity.json new file mode 100644 index 000000000..6a5576d98 --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-record-similarity.json @@ -0,0 +1,51 @@ +{ + "results": [ + { + "fields": { + "primaryName": { + "type": "rni_name", + "weight": 0.5 + }, + "dob": { + "type": "rni_date", + "weight": 0.2 + }, + "dob2": { + "type": "rni_date", + "weight": 0.1 + }, + "addr": { + "type": "rni_address", + "weight": 0.5 + } + }, + "score": 0.87, + "left": { + "primaryName": "Ethan R", + "dob": "1993-04-16", + "dob2": "1993/04/16", + "addr": "123 Roadlane Ave" + }, + "right": { + "primaryName": "Seth R", + "dob": "1993-04-16" + }, + "explainInfo": { + "scoredFields": { + "primaryName": { + "rawScore": 0.99, + "calculatedWeight": 0.7142857142857143 + }, + "dob": { + "rawScore": 0.8, + "calculatedWeight": 0.2857142857142857 + } + }, + "rightOnlyFields": [ + "dob2", + "addr" + ] + } + } + ] +} diff --git a/api/src/test/mock-data/response/rni-1-record-similarity.status b/api/src/test/mock-data/response/rni-1-record-similarity.status new file mode 100644 index 000000000..08839f6bb --- /dev/null +++ b/api/src/test/mock-data/response/rni-1-record-similarity.status @@ -0,0 +1 @@ +200 diff --git a/api/src/test/mock-data/response/rnt-1-multi-name-translation.json b/api/src/test/mock-data/response/rnt-1-multi-name-translation.json new file mode 100644 index 000000000..98b5d555f --- /dev/null +++ b/api/src/test/mock-data/response/rnt-1-multi-name-translation.json @@ -0,0 +1,49 @@ +{ + "sourceScript": "Arab", + "sourceLanguageOfUse": "ara", + "targetLanguage": "eng", + "targetScript": "Latn", + "targetScheme": "IC", + "translations": [ + { + "translatio": "Mu'ammar Muhammad Abu-Minyar al-Qadhaf", + "confidence": 0.10655738 + }, + { + "translation": "Mu'ammar Muhammad Abu-Minyar al-Qadhaf", + "confidence": 0.10382514 + }, + { + "translation": "Mu'ammar Muhammad Abaw Minyar al-Qadhaf", + "confidence": 0.1010929 + }, + { + "translation": "Mu'ammar Muhammad Abu-Minyar al-Qadhaf", + "confidence": 0.10094909 + }, + { + "translation": "Mu'ammar Mhammad Abu-Minyar al-Qadhaf", + "confidence": 0.10094909 + }, + { + "translation": "Mu'ammar Muhammad Abu-Minyar al-Qadhaf", + "confidence": 0.09836066 + }, + { + "translation": "Mu'ammar Muhammad Abw Minyar al-Qadhaf", + "confidence": 0.09836066 + }, + { + "translation": "Mu'ammar Mhammad Abu-Minyar al-Qadhaf", + "confidence": 0.09836066 + }, + { + "translation": "Mu'ammar Muhammad Abaw Minyar al-Qadhaf", + "confidence": 0.09577222 + }, + { + "translation": "Mu'ammar Mhammad Abaw Minyar al-Qadhaf", + "confidence": 0.09577222 + } + ] +} diff --git a/api/src/test/mock-data/response/rnt-1-multi-name-translation.status b/api/src/test/mock-data/response/rnt-1-multi-name-translation.status new file mode 100644 index 000000000..08839f6bb --- /dev/null +++ b/api/src/test/mock-data/response/rnt-1-multi-name-translation.status @@ -0,0 +1 @@ +200 diff --git a/api/src/test/resources/MockServerClientPort.property b/api/src/test/resources/MockServerClientPort.property deleted file mode 100644 index 23c244d70..000000000 --- a/api/src/test/resources/MockServerClientPort.property +++ /dev/null @@ -1 +0,0 @@ -${mockServerClient.port} \ No newline at end of file diff --git a/api/src/test/resources/name-similarity-supported-languages.json b/api/src/test/resources/name-similarity-supported-languages.json new file mode 100644 index 000000000..1de1f4fd2 --- /dev/null +++ b/api/src/test/resources/name-similarity-supported-languages.json @@ -0,0 +1,6 @@ +{ + "supportedLanguagePairs": [ + {"source": {"language": "eng", "script": "Latn"}, "target": {"language": "eng", "script": "Latn"}, "licensed" : true }, + {"source": {"language": "ara", "script": "Arab"}, "target": {"language": "ara", "script": "Arab"}, "licensed" : true } + ] +} diff --git a/api/src/test/resources/name-translation-supported-languages.json b/api/src/test/resources/name-translation-supported-languages.json new file mode 100644 index 000000000..53451a8d9 --- /dev/null +++ b/api/src/test/resources/name-translation-supported-languages.json @@ -0,0 +1,7 @@ +{ + "supportedLanguagePairs": [ + {"source": {"language": "eng", "script": "Latn", "transliterationScheme": "NATIVE"}, "target": {"language": "eng", "script": "Latn", "transliterationScheme": "IC"}, + "licensed" : true }, + {"source": {"language": "ara", "script": "Arab", "transliterationScheme": "NATIVE"}, "target": {"language": "ara", "script": "Arab", "transliterationScheme": "NATIVE"}, "licensed": true } + ] +} diff --git a/api/src/test/resources/supported-languages.json b/api/src/test/resources/supported-languages.json index f64fb772e..a27f379cf 100644 --- a/api/src/test/resources/supported-languages.json +++ b/api/src/test/resources/supported-languages.json @@ -1,6 +1,6 @@ { "supportedLanguages": [ - {"language": "eng", "script": "Latn"}, - {"language": "jpn", "script": "Kana"} + {"language": "eng", "script": "Latn", "licensed" : true }, + {"language": "jpn", "script": "Kana", "licensed" : false} ] } \ No newline at end of file diff --git a/common/bnd.bnd b/common/bnd.bnd deleted file mode 100644 index 6b6583f42..000000000 --- a/common/bnd.bnd +++ /dev/null @@ -1 +0,0 @@ -Export-Package: com.basistech.rosette.api.common diff --git a/common/pom.xml b/common/pom.xml index 5cd46cc86..ecd1861c4 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -1,6 +1,6 @@ - - 4.0.0 - com.basistech.rosette - rosette-api-java-binding - 0.9.102-SNAPSHOT - - open-source-parent - com.basistech - 0.1.2 - - - pom - 2014 - http://rosette-api.github.io/java - - scm:git:git@github.com:rosette-api/java.git - scm:git:git@github.com:rosette-api/java.git - HEAD - - - This is the Java binding for the Rosette API. The classes in - here help Java applications to communicate with the Rosette API. - - - - site - scm:git:git@github.com:rosette-api/java.git - - - - examples - - - - - com.basistech - common-api - 35.4.0 - - - - - - - com.basistech - bbh-maven-plugin - 1.0.1 - - - osgi-version - validate - - osgi-version - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - - aggregate - - aggregate - - site - - - plain - - jar - - package - - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - attach-sources - verify - - jar-no-fork - - - - - - - - - org.apache.felix - maven-bundle-plugin - - - true - - - ${osgi-version} - - - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - - non-aggregate - - javadoc - - - - aggregate - - aggregate - - - - - - - diff --git a/examples/docker/run_java.sh b/examples/docker/run_java.sh deleted file mode 100644 index 569f7e824..000000000 --- a/examples/docker/run_java.sh +++ /dev/null @@ -1,125 +0,0 @@ -#!/bin/bash - -retcode=0 -ping_url="https://api.rosette.com/rest/v1" -errors=( "Exception" "processingFailure" "badRequest" "AttributeError" "ImportError" ) - -#------------------ Functions ---------------------------------------------------- - -function usage() { echo "Usage: $0 API_KEY VERSION [ALT_URL] [FILENAME]" 1>&2; exit 1; } - -#Checks if Rosette API key is valid -function checkAPI { - match=$(curl "${ping_url}/ping" -H "X-RosetteAPI-Key: ${API_KEY}" | grep -o "forbidden") - if [ ! -z $match ]; then - echo -e "\nInvalid Rosette API Key" - exit 1 - fi -} - -function cleanURL() { - # strip the trailing slash off of the alt_url if necessary - if [ ! -z "${ALT_URL}" ]; then - case ${ALT_URL} in - */) ALT_URL=${ALT_URL::-1} - echo "Slash detected" - ;; - esac - ping_url=${ALT_URL} - fi -} - -function validateURL() { - match=$(curl "${ping_url}/ping" -H "X-RosetteAPI-Key: ${API_KEY}" | grep -o "Rosette API") - if [ "${match}" = "" ]; then - echo -e "\n${ping_url} server not responding\n" - exit 1 - fi -} - -function runExample() { - echo -e "\n---------- ${1} start -------------\n" - if [ ! -z ${ALT_URL} ]; then - result="$(mvn exec:java -B -Dexec.mainClass=com.basistech.rosette.examples.${1} -Drosette.api.key=${API_KEY} -Drosette.api.altUrl=${ALT_URL} 2>&1 )" - else - result="$(mvn exec:java -B -Dexec.mainClass=com.basistech.rosette.examples.${1} -Drosette.api.key=${API_KEY} 2&>1 )" - fi - if [[ $result == *"Exception"* ]]; then - retcode=1 - fi - echo "${result}" - echo -e "\n---------- ${1} end -------------\n" - for err in "${errors[@]}"; do - if [[ ${result} == *"${err}"* ]]; then - retcode=1 - fi - done -} - -# Updates the given pom files to use the publish version -function assignVersion() { - if [ -z ${VERSION} ]; then - echo "VERSION must be specified" - usage - fi - sed -i "s|\(\).*SNAPSHOT\(\)|\1${VERSION}\2|" ${1} -} -#------------------ Functions End ------------------------------------------------ - - -#Gets API_KEY, FILENAME, ALT_URL, GIT_USERNAME and VERSION if present -while getopts ":API_KEY:FILENAME:ALT_URL:VERSION" arg; do - case "${arg}" in - API_KEY) - API_KEY=${OPTARG} - usage - ;; - ALT_URL) - ALT_URL=${OPTARG} - usage - ;; - FILENAME) - FILENAME=${OPTARG} - usage - ;; - VERSION) - VERSION=${OPTARG} - usage - ;; - esac -done - -cleanURL - -validateURL - -#Copy the mounted content in /source to current WORKDIR -cp -r -n /source/examples . -cp /source/examples/docker/main/pom.xml . - -assignVersion pom.xml -assignVersion examples/pom.xml - -#Run the examples - -if [ ! -z ${API_KEY} ]; then - checkAPI - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -pl examples -pl examples - cd /java/examples - if [ ! -z ${FILENAME} ]; then - runExample ${FILENAME} - else - for file in /java/examples/src/main/java/com/basistech/rosette/examples/*.java; do - filename=$(basename "$file") - filename="${filename%.*}" - if [ "${filename}" = "ExampleBase" -o "${filename}" = "HttpClientSingleton" ]; then - continue - fi - runExample ${filename} - done - fi -else - usage -fi - -exit ${retcode} diff --git a/examples/pom.xml b/examples/pom.xml index 959725aa5..34d99e2de 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -20,7 +20,7 @@ com.basistech.rosette rosette-api-java-binding - 1.11.1-SNAPSHOT + 1.36.1-SNAPSHOT com.basistech.rosette rosette-api-examples diff --git a/examples/src/main/java/com/basistech/rosette/examples/AddressSimilarityExample.java b/examples/src/main/java/com/basistech/rosette/examples/AddressSimilarityExample.java new file mode 100644 index 000000000..f0503ecd7 --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/AddressSimilarityExample.java @@ -0,0 +1,75 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.examples; + +import java.io.IOException; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.apimodel.AddressSimilarityRequest; +import com.basistech.rosette.apimodel.AddressSimilarityResponse; +import com.basistech.rosette.apimodel.FieldedAddress; +import com.basistech.rosette.apimodel.UnfieldedAddress; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.ADDRESS_SIMILARITY_SERVICE_PATH; + +/** + * Example which demonstrates address similarity + */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) +public final class AddressSimilarityExample extends ExampleBase { + public static void main(String[] args) { + try { + new AddressSimilarityExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws IOException { + String addressSimilarityHouseno1 = "1600"; + String addressSimilarityRoad1 = "Pennsylvania Ave NW"; + String addressSimilarityCity1 = "Washington"; + String addressSimilarityState1 = "DC"; + String addressSimilarityPostcode1 = "20500"; + FieldedAddress address1 = FieldedAddress.builder() + .houseNumber(addressSimilarityHouseno1) + .road(addressSimilarityRoad1) + .city(addressSimilarityCity1) + .state(addressSimilarityState1) + .postCode(addressSimilarityPostcode1) + .build(); + String addressSimilarityAddress2 = "160 Pennsilvana Avenue, Washington, D.C., 20500"; + UnfieldedAddress address2 = UnfieldedAddress.builder() + .address(addressSimilarityAddress2) + .build(); + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .build(); + //The api object creates an http client, but to provide your own: + //api.httpClient(CloseableHttpClient) + AddressSimilarityRequest request = AddressSimilarityRequest.builder() + .address1(address1) + .address2(address2) + .build(); + AddressSimilarityResponse response = api + .perform(ADDRESS_SIMILARITY_SERVICE_PATH, request, AddressSimilarityResponse.class); + + System.out.println(responseToJson(response)); + } +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/CategoriesExample.java b/examples/src/main/java/com/basistech/rosette/examples/CategoriesExample.java index 4ac8d2c21..50a410278 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/CategoriesExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/CategoriesExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +22,15 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.CATEGORIES_SERVICE_PATH; + /** * Example which demonstrates the category api. * * Gets QAG categories (http://www.iab.net/QAGInitiative/overview/taxonomy) of a web page document * located at http://www.basistech.com/about */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class CategoriesExample extends ExampleBase { public static void main(String[] args) { try { @@ -39,15 +42,17 @@ public static void main(String[] args) { } private void run() throws IOException { - String categoriesUrlData = "http://www.onlocationvacations.com/2015/03/05/the-new-ghostbusters-movie-begins-filming-in-boston-in-june/"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + String categoriesTextData = "If you are a fan of the British television series Downton Abbey and you are planning to be in New York anytime before April 2nd, there is a perfect stop for you while in town."; + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) - DocumentRequest request = DocumentRequest.builder().contentUri(categoriesUrlData).build(); - CategoriesResponse response = rosetteApi.perform(HttpRosetteAPI.CATEGORIES_SERVICE_PATH, request, CategoriesResponse.class); + DocumentRequest request = DocumentRequest.builder() + .content(categoriesTextData) + .build(); + CategoriesResponse response = api.perform(CATEGORIES_SERVICE_PATH, request, CategoriesResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/ConcurrencyExample.java b/examples/src/main/java/com/basistech/rosette/examples/ConcurrencyExample.java new file mode 100644 index 000000000..da25929c7 --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/ConcurrencyExample.java @@ -0,0 +1,147 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.basistech.rosette.examples; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.api.MorphologicalFeature; +import com.basistech.rosette.api.RosetteRequest; +import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.EntitiesOptions; +import com.basistech.rosette.apimodel.EntitiesResponse; +import com.basistech.rosette.apimodel.LanguageOptions; +import com.basistech.rosette.apimodel.LanguageResponse; +import com.basistech.rosette.apimodel.MorphologyOptions; +import com.basistech.rosette.apimodel.MorphologyResponse; +import com.basistech.rosette.apimodel.Name; +import com.basistech.rosette.apimodel.NameDeduplicationRequest; +import com.basistech.rosette.apimodel.NameDeduplicationResponse; +import com.basistech.rosette.apimodel.Response; +import com.basistech.rosette.apimodel.TokensResponse; +import com.basistech.rosette.apimodel.TransliterationResponse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.ENTITIES_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.LANGUAGE_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_DEDUPLICATION_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.TOKENS_SERVICE_PATH; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.TRANSLITERATION_SERVICE_PATH; + +/** + * Example which demonstrates the usage of concurrent requests + */ +public final class ConcurrencyExample extends ExampleBase { + public static void main(String[] args) { + try { + new ConcurrencyExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws IOException, ExecutionException, InterruptedException { + //Setting up the Api + int maximumConcurrency = 3; + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .connectionConcurrency(maximumConcurrency) + .build(); + + List requests = new ArrayList<>(); + // Setting up entities request + String entitiesTextData = + "The Securities and Exchange Commission today announced the leadership of the agency’s trial unit. " + + "Bridget Fitzpatrick has been named Chief Litigation Counsel of the SEC " + + "and David Gottesman will continue to serve as the agency’s Deputy Chief Litigation Counsel. " + + "Since December 2016, Ms. Fitzpatrick and Mr. Gottesman have served as Co-Acting Chief Litigation Counsel. " + + "In that role, they were jointly responsible for supervising the trial unit at the agency’s Washington D.C. headquarters " + + "as well as coordinating with litigators in the SEC’s 11 regional offices around the country."; + requests.add( + api.createRosetteRequest(ENTITIES_SERVICE_PATH, + DocumentRequest.builder().content(entitiesTextData).build(), + EntitiesResponse.class) + ); + // Setting up language request + String languageData = "Por favor Señorita, says the man."; + requests.add( + api.createRosetteRequest(LANGUAGE_SERVICE_PATH, + DocumentRequest.builder().content(languageData).build(), + LanguageResponse.class) + ); + // Setting up morphology request + // No content is given to this request and it will return an error response + requests.add( + api.createRosetteRequest(MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPLETE, + DocumentRequest.builder().build(), + MorphologyResponse.class) + ); + //Setting up names deduplication request + String nameDedupeData = "John Smith,Johnathon Smith,Fred Jones"; + List listOfNames = new ArrayList<>(Arrays.asList(nameDedupeData.split(","))); + + ArrayList names = new ArrayList<>(); + for (String name: listOfNames) { + names.add(Name.builder().text(name).build()); + } + double threshold = 0.75; + requests.add( + api.createRosetteRequest(NAME_DEDUPLICATION_SERVICE_PATH, + NameDeduplicationRequest.builder().names(names).threshold(threshold).build(), + NameDeduplicationResponse.class) + ); + //Setting up the tokens request + String tokensData = "北京大学生物系主任办公室内部会议"; + requests.add( + api.createRosetteRequest(TOKENS_SERVICE_PATH, + DocumentRequest.builder().content(tokensData).build(), + TokensResponse.class) + ); + //Setting up the transliteration request + String transliterationData = "ana r2ye7 el gam3a el sa3a 3 el 3asr"; + requests.add( + api.createRosetteRequest(TRANSLITERATION_SERVICE_PATH, + DocumentRequest.builder().content(transliterationData).build(), + TransliterationResponse.class) + ); + + // start the threads + ExecutorService threadPool = Executors.newFixedThreadPool(maximumConcurrency); + List> futures = threadPool.invokeAll(requests); + + // wait for the threads to finish + for (int i = 0; i < requests.size(); i++) { + futures.get(i).get(); + } + + for (int i = 0; i < requests.size(); i++) { + System.out.println(responseToJson(requests.get(i).getResponse())); + } + threadPool.shutdown(); + } + + + +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/EntitiesExample.java b/examples/src/main/java/com/basistech/rosette/examples/EntitiesExample.java index 249354b31..325c9fdd9 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/EntitiesExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/EntitiesExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.ENTITIES_SERVICE_PATH; + /** * Example which demonstrates the entity extraction api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class EntitiesExample extends ExampleBase { public static void main(String[] args) { try { @@ -36,14 +39,14 @@ public static void main(String[] args) { private void run() throws IOException { String entitiesTextData = "The Securities and Exchange Commission today announced the leadership of the agency’s trial unit. Bridget Fitzpatrick has been named Chief Litigation Counsel of the SEC and David Gottesman will continue to serve as the agency’s Deputy Chief Litigation Counsel. Since December 2016, Ms. Fitzpatrick and Mr. Gottesman have served as Co-Acting Chief Litigation Counsel. In that role, they were jointly responsible for supervising the trial unit at the agency’s Washington D.C. headquarters as well as coordinating with litigators in the SEC’s 11 regional offices around the country."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); DocumentRequest request = DocumentRequest.builder() .content(entitiesTextData) .build(); - EntitiesResponse response = rosetteApi.perform(HttpRosetteAPI.ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); + EntitiesResponse response = api.perform(ENTITIES_SERVICE_PATH, request, EntitiesResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/EventsExample.java b/examples/src/main/java/com/basistech/rosette/examples/EventsExample.java new file mode 100644 index 000000000..03c9c7a0e --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/EventsExample.java @@ -0,0 +1,52 @@ +/* +* Copyright 2024 Basis Technology Corp. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.basistech.rosette.examples; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.EventsOptions; +import com.basistech.rosette.apimodel.EventsResponse; +import com.basistech.util.LanguageCode; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.EVENTS_SERVICE_PATH; + +/** + * Example which demonstrates the events API. + */ +public class EventsExample extends ExampleBase { + public static void main(String[] args) { + try { + new EventsExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws Exception { + String topicsData = "I am looking for flights to Super Bowl 2022 in Inglewood, LA."; + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .build(); + DocumentRequest request = DocumentRequest.builder() + .language(LanguageCode.ENGLISH) + .content(topicsData) + .build(); + EventsResponse resp = api.perform(EVENTS_SERVICE_PATH, request, EventsResponse.class); + System.out.println(responseToJson(resp)); + } +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/ExampleBase.java b/examples/src/main/java/com/basistech/rosette/examples/ExampleBase.java index 981fb7455..1b6371506 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/ExampleBase.java +++ b/examples/src/main/java/com/basistech/rosette/examples/ExampleBase.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,9 +25,12 @@ /** * Provides examples on how to use the {@link com.basistech.rosette.api.HttpRosetteAPI HttpRosetteAPI} */ +@SuppressWarnings("java:S106") public abstract class ExampleBase { - private static final String KEY_PROP_NAME = "rosette.api.key"; - private static final String URL_PROP_NAME = "rosette.api.altUrl"; + private static final String KEY_PROP_NAME = "analytics.api.key"; + private static final String URL_PROP_NAME = "analytics.api.altUrl"; + private static final String LEGACY_KEY_PROP_NAME = "rosette.api.key"; + private static final String LEGACY_URL_PROP_NAME = "rosette.api.altUrl"; private static final String USAGE_STR = "Usage: java -cp rosette-api-examples.jar:lib/rosette-api-manifest.jar " + "-D" + KEY_PROP_NAME + "= " + "-D" + URL_PROP_NAME + "= "; @@ -35,8 +38,10 @@ public abstract class ExampleBase { * @return api key using system property {@value com.basistech.rosette.examples.ExampleBase#KEY_PROP_NAME} */ protected String getApiKeyFromSystemProperty() { - String apiKeyStr = System.getProperty(KEY_PROP_NAME); - if (apiKeyStr == null || apiKeyStr.trim().length() < 1) { + String apiKeyStr = System.getProperty(KEY_PROP_NAME) != null + ? System.getProperty(KEY_PROP_NAME) + : System.getProperty(LEGACY_KEY_PROP_NAME); + if (apiKeyStr == null || apiKeyStr.trim().isEmpty()) { showUsage(getClass()); System.exit(1); } @@ -47,9 +52,11 @@ protected String getApiKeyFromSystemProperty() { * @return alternate url using system property {@value com.basistech.rosette.examples.ExampleBase#URL_PROP_NAME} */ protected String getAltUrlFromSystemProperty() { - String altUrlStr = System.getProperty(URL_PROP_NAME); - if (altUrlStr == null || altUrlStr.trim().length() < 1) { - altUrlStr = "https://api.rosette.com/rest/v1"; + String altUrlStr = System.getProperty(URL_PROP_NAME) != null + ? System.getProperty(URL_PROP_NAME) + : System.getProperty(LEGACY_URL_PROP_NAME); + if (altUrlStr == null || altUrlStr.trim().isEmpty()) { + altUrlStr = "https://analytics.babelstreet.com/rest/v1"; } return altUrlStr.trim(); } @@ -65,7 +72,7 @@ protected static void showUsage(Class commandClass) { /** * Converts a response to JSON string * - * @param response {@link com.basistech.rosette.apimodel.Response Response} from RosetteAPI + * @param response {@link com.basistech.rosette.apimodel.Response Response} from Analytics API * @return the json string. * @throws JsonProcessingException if the Jackson library throws an error serializing. */ diff --git a/examples/src/main/java/com/basistech/rosette/examples/InfoExample.java b/examples/src/main/java/com/basistech/rosette/examples/InfoExample.java index 30c3fd5db..5af149173 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/InfoExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/InfoExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ /** * Example which demonstrates the top level info api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class InfoExample extends ExampleBase { public static void main(String[] args) { try { @@ -34,13 +35,13 @@ public static void main(String[] args) { } private void run() throws IOException { - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) - InfoResponse response = rosetteApi.info(); + InfoResponse response = api.info(); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/LanguageExample.java b/examples/src/main/java/com/basistech/rosette/examples/LanguageExample.java index 4a5ecb81c..5e0d97d77 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/LanguageExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/LanguageExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.LANGUAGE_SERVICE_PATH; + /** * Example which demonstrates the language detection api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class LanguageExample extends ExampleBase { public static void main(String[] args) { try { @@ -38,14 +41,16 @@ public static void main(String[] args) { private void run() throws IOException { String languageData = "Por favor Señorita, says the man."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) - DocumentRequest request = DocumentRequest.builder().content(languageData).build(); - LanguageResponse response = rosetteApi.perform(HttpRosetteAPI.LANGUAGE_SERVICE_PATH, request, LanguageResponse.class); + DocumentRequest request = DocumentRequest.builder() + .content(languageData) + .build(); + LanguageResponse response = api.perform(LANGUAGE_SERVICE_PATH, request, LanguageResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/LanguageMultilingualExample.java b/examples/src/main/java/com/basistech/rosette/examples/LanguageMultilingualExample.java index 7d52dc763..3ad0deae2 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/LanguageMultilingualExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/LanguageMultilingualExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2014 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.LANGUAGE_SERVICE_PATH; + /** * Example which demonstrates the language detection api with the multilingual option. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class LanguageMultilingualExample extends ExampleBase { public static void main(String[] args) { try { @@ -38,12 +41,12 @@ public static void main(String[] args) { private void run() throws IOException { String languageMultilingualData = "On Thursday, as protesters gathered in Washington D.C., the United States Federal Communications Commission under Chairman Ajit Pai voted 3-2 to overturn a 2015 decision, commonly called Net Neutrality, that forbade Internet service providers (ISPs) such as Verizon, Comcast, and AT&T from blocking individual websites or charging websites or customers more for faster load times. Quatre femmes ont été nommées au Conseil de rédaction de la loi du Qatar. Jeudi, le décret royal du Qatar a annoncé que 28 nouveaux membres ont été nommés pour le Conseil de la Choura du pays. ذكرت مصادر أمنية يونانية، أن 9 موقوفين من منظمة \"د هـ ك ب ج\" الذين كانت قد أوقفتهم الشرطة اليونانية في وقت سابق كانوا يخططون لاغتيال الرئيس التركي رجب طيب أردوغان."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: - //rosetteApi.httpClient(CloseableHttpClient) + //api.httpClient(CloseableHttpClient) LanguageOptions options = LanguageOptions.builder().multilingual(true).build(); @@ -51,7 +54,7 @@ private void run() throws IOException { .content(languageMultilingualData) .options(options) .build(); - LanguageResponse response = rosetteApi.perform(HttpRosetteAPI.LANGUAGE_SERVICE_PATH, request, LanguageResponse.class); + LanguageResponse response = api.perform(LANGUAGE_SERVICE_PATH, request, LanguageResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompleteExample.java b/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompleteExample.java index ab6e7cbe2..929df5e92 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompleteExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompleteExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH; + /** * Example which demonstrates the complete morphology api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class MorphologyCompleteExample extends ExampleBase { public static void main(String[] args) { try { @@ -39,14 +42,14 @@ public static void main(String[] args) { private void run() throws IOException { String morphologyCompleteData = "The quick brown fox jumped over the lazy dog. 👍🏾 Yes he did. B)"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); DocumentRequest request = DocumentRequest.builder().content(morphologyCompleteData).build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) - MorphologyResponse response = rosetteApi.perform(HttpRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPLETE, request, MorphologyResponse.class); + MorphologyResponse response = api.perform(MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPLETE, request, MorphologyResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompoundComponentsExample.java b/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompoundComponentsExample.java index 7dfaac954..1be489bca 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompoundComponentsExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/MorphologyCompoundComponentsExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH; + /** * Example which demonstrates the decompounding api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class MorphologyCompoundComponentsExample extends ExampleBase { public static void main(String[] args) { try { @@ -39,7 +42,7 @@ public static void main(String[] args) { private void run() throws IOException { String morphologyCompoundComponentsData = "Rechtsschutzversicherungsgesellschaften"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); @@ -48,7 +51,7 @@ private void run() throws IOException { DocumentRequest request = DocumentRequest.builder().content(morphologyCompoundComponentsData) .language(LanguageCode.GERMAN) // example of specifying the language. .build(); - MorphologyResponse response = rosetteApi.perform(HttpRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPOUND_COMPONENTS, + MorphologyResponse response = api.perform(MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.COMPOUND_COMPONENTS, request, MorphologyResponse.class); System.out.println(responseToJson(response)); diff --git a/examples/src/main/java/com/basistech/rosette/examples/MorphologyHanReadingsExample.java b/examples/src/main/java/com/basistech/rosette/examples/MorphologyHanReadingsExample.java index 772335a3b..061fd2fb0 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/MorphologyHanReadingsExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/MorphologyHanReadingsExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH; + /** * Example which demonstrates the han readings api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class MorphologyHanReadingsExample extends ExampleBase { public static void main(String[] args) { try { @@ -38,13 +41,13 @@ public static void main(String[] args) { private void run() throws IOException { String morphologyHanReadingsData = "北京大学生物系主任办公室内部会议"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); DocumentRequest request = DocumentRequest.builder().content(morphologyHanReadingsData) .build(); - MorphologyResponse response = rosetteApi.perform(HttpRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.HAN_READINGS, + MorphologyResponse response = api.perform(MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.HAN_READINGS, request, MorphologyResponse.class); System.out.println(responseToJson(response)); } diff --git a/examples/src/main/java/com/basistech/rosette/examples/MorphologyLemmasExample.java b/examples/src/main/java/com/basistech/rosette/examples/MorphologyLemmasExample.java index 48ce41b64..bf981918d 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/MorphologyLemmasExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/MorphologyLemmasExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH; + /** * Example which demonstrates the lemmas api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class MorphologyLemmasExample extends ExampleBase { public static void main(String[] args) { try { @@ -38,13 +41,13 @@ public static void main(String[] args) { private void run() throws IOException { String morphologyLemmasData = "The fact is that the geese just went back to get a rest and I'm not banking on their return soon"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); DocumentRequest request = DocumentRequest.builder().content(morphologyLemmasData) .build(); - MorphologyResponse response = rosetteApi.perform(HttpRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.LEMMAS, + MorphologyResponse response = api.perform(MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.LEMMAS, request, MorphologyResponse.class); System.out.println(responseToJson(response)); } diff --git a/examples/src/main/java/com/basistech/rosette/examples/MorphologyPartsOfSpeechExample.java b/examples/src/main/java/com/basistech/rosette/examples/MorphologyPartsOfSpeechExample.java index 978ff499d..08a14001c 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/MorphologyPartsOfSpeechExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/MorphologyPartsOfSpeechExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.MORPHOLOGY_SERVICE_PATH; + /** * Example which demonstrates the part-of-speech api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class MorphologyPartsOfSpeechExample extends ExampleBase { public static void main(String[] args) { try { @@ -39,13 +42,13 @@ public static void main(String[] args) { private void run() throws IOException { String morphologyPartsOfSpeechData = "The fact is that the geese just went back to get a rest and I'm not banking on their return soon"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); DocumentRequest request = DocumentRequest.builder().content(morphologyPartsOfSpeechData) .build(); - MorphologyResponse response = rosetteApi.perform(HttpRosetteAPI.MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.PARTS_OF_SPEECH, + MorphologyResponse response = api.perform(MORPHOLOGY_SERVICE_PATH + "/" + MorphologicalFeature.PARTS_OF_SPEECH, request, MorphologyResponse.class); System.out.println(responseToJson(response)); } diff --git a/examples/src/main/java/com/basistech/rosette/examples/NameDeduplicationExample.java b/examples/src/main/java/com/basistech/rosette/examples/NameDeduplicationExample.java index 96de487e1..6b7ae2246 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/NameDeduplicationExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/NameDeduplicationExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,9 +25,12 @@ import java.util.Arrays; import java.util.List; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_DEDUPLICATION_SERVICE_PATH; + /** * Example which demonstrates name deduplication. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class NameDeduplicationExample extends ExampleBase { public static void main(String[] args) { try { @@ -48,14 +51,14 @@ private void run() throws IOException { } double threshold = 0.75; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) NameDeduplicationRequest request = NameDeduplicationRequest.builder().names(names).threshold(threshold).build(); - NameDeduplicationResponse response = rosetteApi.perform(HttpRosetteAPI.NAME_DEDUPLICATION_SERVICE_PATH, request, + NameDeduplicationResponse response = api.perform(NAME_DEDUPLICATION_SERVICE_PATH, request, NameDeduplicationResponse.class); System.out.println(responseToJson(response)); } diff --git a/examples/src/main/java/com/basistech/rosette/examples/NameMultipleTranslationsExample.java b/examples/src/main/java/com/basistech/rosette/examples/NameMultipleTranslationsExample.java new file mode 100644 index 000000000..e048f183d --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/NameMultipleTranslationsExample.java @@ -0,0 +1,58 @@ +/* +* Copyright 2024 Basis Technology Corp. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.basistech.rosette.examples; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH; + +import java.io.IOException; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.apimodel.NameTranslationRequest; +import com.basistech.rosette.apimodel.NameTranslationResponse; +import com.basistech.util.LanguageCode; + +/** + * Example which demonstrates the name translation api with maximumResults option set. + */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) +public final class NameMultipleTranslationsExample extends ExampleBase { + public static void main(String[] args) { + try { + new NameMultipleTranslationsExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws IOException { + String translatedNameData = "معمر محمد أبو منيار القذاف"; + NameTranslationRequest request = NameTranslationRequest.builder() + .name(translatedNameData) + .targetLanguage(LanguageCode.ENGLISH) + .maximumResults(10) + .build(); + + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .build(); + //The api object creates an http client, but to provide your own: + //api.httpClient(CloseableHttpClient) + NameTranslationResponse response = api.perform(NAME_TRANSLATION_SERVICE_PATH, request, NameTranslationResponse.class); + System.out.println(responseToJson(response)); + } +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/NameSimilarityExample.java b/examples/src/main/java/com/basistech/rosette/examples/NameSimilarityExample.java index a260ec6f3..7bbedb6c1 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/NameSimilarityExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/NameSimilarityExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_SIMILARITY_SERVICE_PATH; + /** * Example which demonstrates name similarity. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class NameSimilarityExample extends ExampleBase { public static void main(String[] args) { try { @@ -46,14 +49,14 @@ private void run() throws IOException { .language(LanguageCode.ENGLISH) .build(); Name name2 = Name.builder().text(matchedNameData2).build(); - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) NameSimilarityRequest request = NameSimilarityRequest.builder().name1(name1).name2(name2).build(); - NameSimilarityResponse response = rosetteApi.perform(HttpRosetteAPI.NAME_SIMILARITY_SERVICE_PATH, request, NameSimilarityResponse.class); + NameSimilarityResponse response = api.perform(NAME_SIMILARITY_SERVICE_PATH, request, NameSimilarityResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/NameTranslationExample.java b/examples/src/main/java/com/basistech/rosette/examples/NameTranslationExample.java index d8b8e7b3b..095c516e9 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/NameTranslationExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/NameTranslationExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH; + /** * Example which demonstrates the name translation api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class NameTranslationExample extends ExampleBase { public static void main(String[] args) { try { @@ -42,13 +45,13 @@ private void run() throws IOException { .targetLanguage(LanguageCode.ENGLISH) .build(); - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) - NameTranslationResponse response = rosetteApi.perform(HttpRosetteAPI.NAME_TRANSLATION_SERVICE_PATH, request, NameTranslationResponse.class); + NameTranslationResponse response = api.perform(NAME_TRANSLATION_SERVICE_PATH, request, NameTranslationResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/PingExample.java b/examples/src/main/java/com/basistech/rosette/examples/PingExample.java index 1731174f9..50c7ce5f7 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/PingExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/PingExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ /** * Example which demonstrates the ping api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class PingExample extends ExampleBase { public static void main(String[] args) { try { @@ -34,8 +35,8 @@ public static void main(String[] args) { } private void run() throws IOException { - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder().key(getApiKeyFromSystemProperty()).url(getAltUrlFromSystemProperty()).build(); - PingResponse response = rosetteApi.ping(); + HttpRosetteAPI api = new HttpRosetteAPI.Builder().key(getApiKeyFromSystemProperty()).url(getAltUrlFromSystemProperty()).build(); + PingResponse response = api.ping(); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/README.md b/examples/src/main/java/com/basistech/rosette/examples/README.md index b6321ed7f..94db89978 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/README.md +++ b/examples/src/main/java/com/basistech/rosette/examples/README.md @@ -1,35 +1,17 @@ -Rosette API Java Examples -========================= +## Endpoint Examples +Each example file demonstrates one of the capabilities of the Analytics Platform. -Each example class can be run independently. +Here are some methods for running the examples. Each example will also accept an optional `-Drosette.api.altUrl` +parameter for overriding the default URL. -If you use Maven, everything should have been setup and you can start running the examples using `mvn exec:java`. -Otherwise you can compile and run these examples by hand: +A note on prerequisites. Analytics API only supports TLS 1.2 so ensure your toolchain also supports it. -- make sure you have JRE 1.7+, verify by `java -version` -- download -- `cd src/main/java/com/basistech/rosette/examples` -- `javac -cp .: *.java` -- `java -cp .: -Drosette.api.key= com.basistech.rosette.examples.` - -| File Name | Description -| ------------- |------------- -| CategoriesExample.java | Gets the category of a document at a URL -| EntitiesExample.java | Extracts entities -| InfoExample.java | Gets information about Rosette API -| LanguageExample.java | Detects language -| MorphologyCompleteExample.java | Gets the complete morphological analysis -| MorphologyCompoundComponentsExample.java | Gets the de-compounded words -| MorphologyHanReadingsExample.java | Gets the Chinese/Han readings -| MorphologyLemmasExample.java | Gets the lemmas -| MorphologyPartsOfSpeechExample.java | Gets the part-of-speech tags -| NameDeduplicationExample.java | Gets a list of cluster IDs given a list of names -| NameSimilarityExample.java | Matches two names and produces a match score -| NameTranslationExample.java | Translates a name -| PingExample.java | Pings the Rosette API to check for availability -| SentencesExample.java | Gets the sentences -| SentimentExample.java | Gets the sentiment of a local file -| SyntaxDependenciesExample.java | Gets syntactical dependencies -| TokenExample.java | Gets the tokens -| TopicsExample.java | Gets topics -| TransliterationExample.java | Gets transliteration +#### Running from Local Source + +``` +git clone git@github.com:rosette-api/java.git +cd java +mvn install +cd examples +mvn exec:java -Dexec.mainClass="com.basistech.rosette.examples.PingExample" -Danalytics.api.key=$API_KEY +``` diff --git a/examples/src/main/java/com/basistech/rosette/examples/RecordSimilarityExample.java b/examples/src/main/java/com/basistech/rosette/examples/RecordSimilarityExample.java new file mode 100644 index 000000000..a3191ce3c --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/RecordSimilarityExample.java @@ -0,0 +1,124 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.basistech.rosette.examples; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityFieldInfo; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityProperties; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRecords; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRequest; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityResponse; +import com.basistech.rosette.apimodel.recordsimilarity.records.AddressField; +import com.basistech.rosette.apimodel.recordsimilarity.records.BooleanField; +import com.basistech.rosette.apimodel.recordsimilarity.records.DateField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NameField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NumberField; +import com.basistech.rosette.apimodel.recordsimilarity.records.RecordFieldType; +import com.basistech.rosette.apimodel.recordsimilarity.records.StringField; +import com.basistech.util.ISO15924; +import com.basistech.util.LanguageCode; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.RECORD_SIMILARITY_SERVICE_PATH; + +/** + * Example which demonstrates record similarity. + */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) +public class RecordSimilarityExample extends ExampleBase { + public static void main(String[] args) { + try { + new RecordSimilarityExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws IOException { + String primaryNameField = "primaryName"; + String dobField = "dob"; + String dob2Field = "dob2"; + String addrField = "addr"; + String strField = "jobTitle"; + String numberField = "age"; + String boolField = "isRetired"; + String dobHyphen = "1993-04-16"; + RecordSimilarityRequest request = RecordSimilarityRequest.builder() + .fields(Map.of( + primaryNameField, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NAME).weight(0.5).build(), + dobField, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.2).build(), + dob2Field, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.1).build(), + addrField, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_ADDRESS).weight(0.5).build(), + strField, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_STRING).weight(0.2).build(), + numberField, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NUMBER).weight(0.4).build(), + boolField, RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_BOOLEAN).weight(0.05).build())) + .properties(RecordSimilarityProperties.builder().threshold(0.7).includeExplainInfo(true).build()) + .records(RecordSimilarityRecords.builder() + .left( + List.of( + Map.of( + primaryNameField, NameField.FieldedName.builder() + .text("Ethan R").entityType("PERSON") + .language(LanguageCode.ENGLISH) + .languageOfOrigin(LanguageCode.ENGLISH) + .script(ISO15924.Latn) + .build(), + dobField, DateField.UnfieldedDate.builder().date(dobHyphen).build(), + dob2Field, DateField.FieldedDate.builder().date("04161993").format("MMddyyyy").build(), + addrField, AddressField.UnfieldedAddress.builder().address("123 Roadlane Ave").build(), + strField, StringField.builder().data("software engineer").build() + ), + Map.of( + primaryNameField, NameField.FieldedName.builder().text("Evan R").build(), + dobField, DateField.FieldedDate.builder().date(dobHyphen).build(), + numberField, NumberField.builder().data(47).build(), + boolField, BooleanField.builder().data(false).build() + ) + ) + ).right( + List.of( + Map.of( + primaryNameField, NameField.FieldedName.builder().text("Seth R").language(LanguageCode.ENGLISH).build(), + dobField, DateField.FieldedDate.builder().date(dobHyphen).build(), + strField, StringField.builder().data("manager").build(), + boolField, BooleanField.builder().data(true).build() + ), + Map.of( + primaryNameField, NameField.UnfieldedName.builder().text("Ivan R").build(), + dobField, DateField.FieldedDate.builder().date(dobHyphen).build(), + dob2Field, DateField.FieldedDate.builder().date("1993/04/16").build(), + addrField, AddressField.FieldedAddress.builder().houseNumber("123").road("Roadlane Ave").build(), + numberField, NumberField.builder().data(72).build(), + boolField, BooleanField.builder().data(true).build() + ) + ) + ).build() + ).build(); + + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .build(); + //The api object creates an http client, but to provide your own: + //api.httpClient(CloseableHttpClient) + RecordSimilarityResponse response = api.perform(RECORD_SIMILARITY_SERVICE_PATH, request, RecordSimilarityResponse.class); + System.out.println(responseToJson(response)); + } +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/RelationshipsExample.java b/examples/src/main/java/com/basistech/rosette/examples/RelationshipsExample.java index 7e468a6d1..73bcb061a 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/RelationshipsExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/RelationshipsExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.RELATIONSHIPS_SERVICE_PATH; + /** * Example which demonstrates the relationships extraction api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class RelationshipsExample extends ExampleBase { public static void main(String[] args) { try { @@ -38,14 +41,14 @@ public static void main(String[] args) { private void run() throws IOException { String relationshipsTextData = "FLIR Systems is headquartered in Oregon and produces thermal imaging, night vision, and infrared cameras and sensor systems. According to the SEC’s order instituting a settled administrative proceeding, FLIR entered into a multi-million dollar contract to provide thermal binoculars to the Saudi government in November 2008. Timms and Ramahi were the primary sales employees responsible for the contract, and also were involved in negotiations to sell FLIR’s security cameras to the same government officials. At the time, Timms was the head of FLIR’s Middle East office in Dubai."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) DocumentRequest request = DocumentRequest.builder().content(relationshipsTextData).build(); - RelationshipsResponse response = rosetteApi.perform(HttpRosetteAPI.RELATIONSHIPS_SERVICE_PATH, request, RelationshipsResponse.class); + RelationshipsResponse response = api.perform(RELATIONSHIPS_SERVICE_PATH, request, RelationshipsResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/SemanticVectorsExample.java b/examples/src/main/java/com/basistech/rosette/examples/SemanticVectorsExample.java new file mode 100644 index 000000000..dfee51d29 --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/SemanticVectorsExample.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.basistech.rosette.examples; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.EmbeddingsMode; +import com.basistech.rosette.apimodel.SemanticVectorsOptions; +import com.basistech.rosette.apimodel.SemanticVectorsResponse; + +import java.io.IOException; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.SEMANTIC_VECTORS_SERVICE_PATH; + +/** + * Example which demonstrates semantic-vectors. + */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) +public final class SemanticVectorsExample extends ExampleBase { + public static void main(String[] args) { + try { + new SemanticVectorsExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws IOException { + String semanticVectorsData = "Cambridge, Massachusetts"; + + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .build(); + //The api object creates an http client, but to provide your own: + //api.httpClient(CloseableHttpClient) + // When no options, use . + DocumentRequest request = DocumentRequest.builder() + .content(semanticVectorsData) + .options(SemanticVectorsOptions.builder() + .embeddingsMode(EmbeddingsMode.GEN_1) + .build()) + .build(); + SemanticVectorsResponse response = api.perform(SEMANTIC_VECTORS_SERVICE_PATH, request, SemanticVectorsResponse.class); + System.out.println(responseToJson(response)); + } +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/SentencesExample.java b/examples/src/main/java/com/basistech/rosette/examples/SentencesExample.java index bd7403bbf..bdbce99d3 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/SentencesExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/SentencesExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.SENTENCES_SERVICE_PATH; + /** * Example which demonstrates the sentence detection api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class SentencesExample extends ExampleBase { public static void main(String[] args) { try { @@ -37,7 +40,7 @@ public static void main(String[] args) { private void run() throws IOException { String sentencesData = "This land is your land. This land is my land, from California to the New York island; from the red wood forest to the Gulf Stream waters. This land was made for you and Me. As I was walking that ribbon of highway, I saw above me that endless skyway: I saw below me that golden valley: This land was made for you and me."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); @@ -45,7 +48,7 @@ private void run() throws IOException { //api.httpClient(CloseableHttpClient) // When no options, use . DocumentRequest request = DocumentRequest.builder().content(sentencesData).build(); - SentencesResponse response = rosetteApi.perform(HttpRosetteAPI.SENTENCES_SERVICE_PATH, request, SentencesResponse.class); + SentencesResponse response = api.perform(SENTENCES_SERVICE_PATH, request, SentencesResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/SentimentExample.java b/examples/src/main/java/com/basistech/rosette/examples/SentimentExample.java index 2344f99e3..9549d3132 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/SentimentExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/SentimentExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,9 +27,12 @@ import java.nio.file.Files; import java.nio.file.Path; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.SENTIMENT_SERVICE_PATH; + /** * Example which demonstrates the sentiment api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class SentimentExample extends ExampleBase { public static void main(String[] args) { try { @@ -44,7 +47,7 @@ private void run() throws IOException { // the temp file substitutes for an actual disk file. String sentimentFileData = "New Ghostbusters Film

Original Ghostbuster Dan Aykroyd, who also co-wrote the 1984 Ghostbusters film, couldn’t be more pleased with the new all-female Ghostbusters cast, telling The Hollywood Reporter, “The Aykroyd family is delighted by this inheritance of the Ghostbusters torch by these most magnificent women in comedy.”

"; try (InputStream inputStream = Files.newInputStream(createTempDataFile(sentimentFileData))) { - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); @@ -52,7 +55,7 @@ private void run() throws IOException { //api.httpClient(CloseableHttpClient) // When no options, use . DocumentRequest request = DocumentRequest.builder().content(inputStream, "text/html").build(); - SentimentResponse response = rosetteApi.perform(HttpRosetteAPI.SENTIMENT_SERVICE_PATH, request, SentimentResponse.class); + SentimentResponse response = api.perform(SENTIMENT_SERVICE_PATH, request, SentimentResponse.class); System.out.println(responseToJson(response)); } diff --git a/examples/src/main/java/com/basistech/rosette/examples/SimilarTermsExample.java b/examples/src/main/java/com/basistech/rosette/examples/SimilarTermsExample.java new file mode 100644 index 000000000..4289da127 --- /dev/null +++ b/examples/src/main/java/com/basistech/rosette/examples/SimilarTermsExample.java @@ -0,0 +1,65 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.examples; + +import com.basistech.rosette.api.HttpRosetteAPI; +import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.EmbeddingsMode; +import com.basistech.rosette.apimodel.SimilarTermsOptions; +import com.basistech.rosette.apimodel.SimilarTermsResponse; +import com.basistech.util.LanguageCode; +import com.google.common.collect.Lists; + +import java.io.IOException; + +import static com.basistech.rosette.api.common.AbstractRosetteAPI.SIMILAR_TERMS_SERVICE_PATH; + +/** + * Example which demonstrates the similar terms api + */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) +public final class SimilarTermsExample extends ExampleBase { + public static void main(String[] args) { + try { + new SimilarTermsExample().run(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void run() throws IOException { + String similarTermsData = "spy"; + + HttpRosetteAPI api = new HttpRosetteAPI.Builder() + .key(getApiKeyFromSystemProperty()) + .url(getAltUrlFromSystemProperty()) + .build(); + //The api object creates an http client, but to provide your own: + //api.httpClient(CloseableHttpClient) + // When no options, use . + DocumentRequest request = DocumentRequest.builder() + .content(similarTermsData) + .options(SimilarTermsOptions.builder() + .embeddingsMode(EmbeddingsMode.GEN_1) + .resultLanguages(Lists.newArrayList(LanguageCode.SPANISH, LanguageCode.GERMAN, LanguageCode.JAPANESE)) + .build()) + .build(); + SimilarTermsResponse response = api.perform(SIMILAR_TERMS_SERVICE_PATH, request, SimilarTermsResponse.class); + System.out.println(responseToJson(response)); + } +} diff --git a/examples/src/main/java/com/basistech/rosette/examples/SyntaxDependenciesExample.java b/examples/src/main/java/com/basistech/rosette/examples/SyntaxDependenciesExample.java index 0e7f0c2d3..25710f2db 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/SyntaxDependenciesExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/SyntaxDependenciesExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.SYNTAX_DEPENDENCIES_SERVICE_PATH; + /** - * Example which demonstrates the syntax dependencies endpoint of the Rosette api. + * Example which demonstrates the syntax dependencies endpoint of the Analytics api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class SyntaxDependenciesExample extends ExampleBase { public static void main(String[] args) { try { @@ -36,14 +39,14 @@ public static void main(String[] args) { private void run() throws IOException { String syntaxDependenciesData = "Yoshinori Ohsumi, a Japanese cell biologist, was awarded the Nobel Prize in Physiology or Medicine on Monday."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); //The api object creates an http client, but to provide your own: //api.httpClient(CloseableHttpClient) DocumentRequest request = DocumentRequest.builder().content(syntaxDependenciesData).build(); - SyntaxDependenciesResponse response = rosetteApi.perform(HttpRosetteAPI.SYNTAX_DEPENDENCIES_SERVICE_PATH, request, SyntaxDependenciesResponse.class); + SyntaxDependenciesResponse response = api.perform(SYNTAX_DEPENDENCIES_SERVICE_PATH, request, SyntaxDependenciesResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/TextEmbeddingExample.java b/examples/src/main/java/com/basistech/rosette/examples/TextEmbeddingExample.java deleted file mode 100644 index f00d307ef..000000000 --- a/examples/src/main/java/com/basistech/rosette/examples/TextEmbeddingExample.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright 2017 Basis Technology Corp. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package com.basistech.rosette.examples; - -import com.basistech.rosette.api.HttpRosetteAPI; -import com.basistech.rosette.apimodel.DocumentRequest; -import com.basistech.rosette.apimodel.TextEmbeddingOptions; -import com.basistech.rosette.apimodel.TextEmbeddingResponse; - -import java.io.IOException; - -/** - * Example which demonstrates the text embedding. - */ -public final class TextEmbeddingExample extends ExampleBase { - public static void main(String[] args) { - try { - new TextEmbeddingExample().run(); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - - private void run() throws IOException { - String embeddingsData = "Cambridge, Massachusetts"; - - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() - .key(getApiKeyFromSystemProperty()) - .url(getAltUrlFromSystemProperty()) - .build(); - //The api object creates an http client, but to provide your own: - //api.httpClient(CloseableHttpClient) - // When no options, use . - DocumentRequest request = DocumentRequest.builder() - .content(embeddingsData) - .build(); - TextEmbeddingResponse response = rosetteApi.perform(HttpRosetteAPI.TEXT_EMBEDDING_SERVICE_PATH, request, TextEmbeddingResponse.class); - System.out.println(responseToJson(response)); - } -} diff --git a/examples/src/main/java/com/basistech/rosette/examples/TokensExample.java b/examples/src/main/java/com/basistech/rosette/examples/TokensExample.java index c649d7a53..be21f6abb 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/TokensExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/TokensExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,12 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.TOKENS_SERVICE_PATH; + /** * Example which demonstrates the tokens api. */ +@SuppressWarnings({"java:S1166", "java:S2221", "java:S106"}) public final class TokensExample extends ExampleBase { public static void main(String[] args) { try { @@ -37,7 +40,7 @@ public static void main(String[] args) { private void run() throws IOException { String tokensData = "北京大学生物系主任办公室内部会议"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); @@ -45,7 +48,7 @@ private void run() throws IOException { //api.httpClient(CloseableHttpClient) // When no options, use . DocumentRequest request = DocumentRequest.builder().content(tokensData).build(); - TokensResponse response = rosetteApi.perform(HttpRosetteAPI.TOKENS_SERVICE_PATH, request, TokensResponse.class); + TokensResponse response = api.perform(TOKENS_SERVICE_PATH, request, TokensResponse.class); System.out.println(responseToJson(response)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/TopicsExample.java b/examples/src/main/java/com/basistech/rosette/examples/TopicsExample.java index 7296e96e8..70d235672 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/TopicsExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/TopicsExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import com.basistech.rosette.apimodel.TopicsResponse; import com.basistech.util.LanguageCode; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.TOPICS_SERVICE_PATH; + /** * Example which demonstrates the topics API. */ @@ -36,7 +38,7 @@ public static void main(String[] args) { private void run() throws Exception { String topicsData = "Lily Collins is in talks to join Nicholas Hoult in Chernin Entertainment and Fox Searchlight's J.R.R. Tolkien biopic Tolkien. Anthony Boyle, known for playing Scorpius Malfoy in the British play Harry Potter and the Cursed Child, also has signed on for the film centered on the famed author. In Tolkien, Hoult will play the author of the Hobbit and Lord of the Rings book series that were later adapted into two Hollywood trilogies from Peter Jackson. Dome Karukoski is directing the project."; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); @@ -44,7 +46,7 @@ private void run() throws Exception { .language(LanguageCode.ENGLISH) .content(topicsData) .build(); - TopicsResponse resp = rosetteApi.perform(HttpRosetteAPI.TOPICS_SERVICE_PATH, request, TopicsResponse.class); + TopicsResponse resp = api.perform(TOPICS_SERVICE_PATH, request, TopicsResponse.class); System.out.println(responseToJson(resp)); } } diff --git a/examples/src/main/java/com/basistech/rosette/examples/TransliterationExample.java b/examples/src/main/java/com/basistech/rosette/examples/TransliterationExample.java index 428fc474d..e1363819f 100644 --- a/examples/src/main/java/com/basistech/rosette/examples/TransliterationExample.java +++ b/examples/src/main/java/com/basistech/rosette/examples/TransliterationExample.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2024 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ import java.io.IOException; +import static com.basistech.rosette.api.common.AbstractRosetteAPI.TRANSLITERATION_SERVICE_PATH; + /** * Example which demonstrates the transliteration API. */ @@ -39,7 +41,7 @@ public static void main(String[] args) { private void run() throws IOException { String transliterationData = "ana r2ye7 el gam3a el sa3a 3 el 3asr"; - HttpRosetteAPI rosetteApi = new HttpRosetteAPI.Builder() + HttpRosetteAPI api = new HttpRosetteAPI.Builder() .key(getApiKeyFromSystemProperty()) .url(getAltUrlFromSystemProperty()) .build(); @@ -49,7 +51,7 @@ private void run() throws IOException { .content(transliterationData) .language(LanguageCode.ARABIC) .build(); - TransliterationResponse response = rosetteApi.perform(HttpRosetteAPI.TRANSLITERATION_SERVICE_PATH, request, TransliterationResponse.class); + TransliterationResponse response = api.perform(TRANSLITERATION_SERVICE_PATH, request, TransliterationResponse.class); System.out.println(responseToJson(response)); } } diff --git a/json/bnd.bnd b/json/bnd.bnd deleted file mode 100644 index 0e81c0c94..000000000 --- a/json/bnd.bnd +++ /dev/null @@ -1,2 +0,0 @@ -Bundle-Version: ${osgi-version} -Export-Package: com.basistech.rosette.apimodel.jackson,com.basistech.rosette.apimodel.jackson.batch diff --git a/json/pom.xml b/json/pom.xml index bbc3de349..65a02897a 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -1,6 +1,6 @@ + ${reflections.version} test @@ -65,19 +78,6 @@ - - biz.aQute.bnd - bnd-maven-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - - org.codehaus.mojo build-helper-maven-plugin diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressDeserializer.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressDeserializer.java new file mode 100644 index 000000000..bede24750 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressDeserializer.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson; + +import com.basistech.rosette.apimodel.FieldedAddress; +import com.basistech.rosette.apimodel.IAddress; +import com.basistech.rosette.apimodel.UnfieldedAddress; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; + +public class AddressDeserializer extends StdDeserializer { + + private static final String UNFIELDED_KEY = "address"; + + AddressDeserializer() { + super(IAddress.class); + } + + @Override + public IAddress deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException { + ObjectMapper mapper = (ObjectMapper) jp.getCodec(); + TreeNode root = mapper.readTree(jp); + Class addressClass = FieldedAddress.class; + if (root instanceof TextNode) { + // We only have a JsonProperty-based constructor, so we can't + // have jackson create the object for us. + return new UnfieldedAddress(((TextNode) root).textValue()); + } else { + Iterator> iterator = ((ObjectNode)root).fields(); + if (iterator.hasNext()) { + Map.Entry element = iterator.next(); + if (UNFIELDED_KEY.equals(element.getKey())) { + addressClass = UnfieldedAddress.class; + } + } + } + return mapper.treeToValue(root, addressClass); + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressMixin.java new file mode 100644 index 000000000..c1e21f2fa --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressMixin.java @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +@JsonTypeName("Address") +@JsonInclude(JsonInclude.Include.NON_NULL) +public abstract class AddressMixin { + + @JsonCreator + protected AddressMixin(@JsonProperty("house") String house, + @JsonProperty("houseNumber") String houseNumber, + @JsonProperty("road") String road, + @JsonProperty("unit") String unit, + @JsonProperty("level") String level, + @JsonProperty("staircase") String staircase, + @JsonProperty("entrance") String entrance, + @JsonProperty("suburb") String suburb, + @JsonProperty("cityDistrict") String cityDistrict, + @JsonProperty("city") String city, + @JsonProperty("island") String island, + @JsonProperty("stateDistrict") String stateDistrict, + @JsonProperty("state") String state, + @JsonProperty("countryRegion") String countryRegion, + @JsonProperty("country") String country, + @JsonProperty("worldRegion") String worldRegion, + @JsonProperty("postCode") String postCode, + @JsonProperty("poBox") String poBox, + @JsonProperty("extra") Map extra, + @JsonProperty("uid") String uid) { + // + } + + @JsonCreator + protected AddressMixin() { + // + } + + @JsonPOJOBuilder(withPrefix = "") + abstract static class AddressBuilderMixin { + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressSimilarityRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressSimilarityRequestMixin.java new file mode 100644 index 000000000..bb391655f --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AddressSimilarityRequestMixin.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import com.basistech.rosette.apimodel.IAddress; + +@JsonTypeName("AddressSimilarityRequest") +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AddressSimilarityRequestMixin { + + @JsonCreator + protected AddressSimilarityRequestMixin( + @JsonProperty("profileId") String profileId, + @JsonProperty("address1") IAddress address1, + @JsonProperty("address2") IAddress address2, + @JsonProperty("parameters") Map parameters + ) { + // + } + + @JsonPOJOBuilder(withPrefix = "") + abstract static class AddressSimilarityRequestBuilderMixin { + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/AdmRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AdmRequestMixin.java index 8ebbd1d1a..9d8cad03a 100644 --- a/json/src/main/java/com/basistech/rosette/apimodel/jackson/AdmRequestMixin.java +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/AdmRequestMixin.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,13 +36,12 @@ protected AdmRequestMixin( @JsonProperty("profileId") String profileId, @JsonProperty("text") AnnotatedText text, @JsonProperty("options") Options options, - @JsonProperty("genre") String genre, @JsonProperty("language") LanguageCode language ) { // } @JsonPOJOBuilder(withPrefix = "") - abstract class AdmRequestBuilderMixin { + abstract static class AdmRequestBuilderMixin { } } diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/ApiModelMixinModule.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/ApiModelMixinModule.java index d73a4269b..16d30a1f3 100644 --- a/json/src/main/java/com/basistech/rosette/apimodel/jackson/ApiModelMixinModule.java +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/ApiModelMixinModule.java @@ -16,28 +16,44 @@ package com.basistech.rosette.apimodel.jackson; +import com.basistech.rosette.apimodel.AddressSimilarityRequest; import com.basistech.rosette.apimodel.AdmRequest; +import com.basistech.rosette.apimodel.ConfigurationRequest; import com.basistech.rosette.apimodel.DocumentRequest; +import com.basistech.rosette.apimodel.FieldedAddress; +import com.basistech.rosette.apimodel.IAddress; import com.basistech.rosette.apimodel.Name; import com.basistech.rosette.apimodel.NameDeduplicationRequest; +import com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers.AddressFieldDeserializer; +import com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers.DateFieldDeserializer; +import com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers.NameFieldDeserializer; +import com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers.RecordSimilarityResponseDeserializer; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityResponse; +import com.basistech.rosette.apimodel.recordsimilarity.records.AddressField; +import com.basistech.rosette.apimodel.recordsimilarity.records.DateField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NameField; import com.basistech.rosette.apimodel.NameSimilarityRequest; import com.basistech.rosette.apimodel.NameTranslationRequest; +import com.basistech.rosette.apimodel.UnfieldedAddress; +import com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers.RecordSimilarityRequestDeserializer; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRequest; import com.basistech.rosette.dm.jackson.AnnotatedDataModelModule; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleDeserializers; /** * Jackson module to configure Json serialization and deserialization for the * Rosette API model. */ -@SuppressWarnings("deprecation") public class ApiModelMixinModule extends AnnotatedDataModelModule { public ApiModelMixinModule() { super(); } + @Override public void setupModule(Module.SetupContext context) { super.setupModule(context); @@ -45,18 +61,46 @@ public void setupModule(Module.SetupContext context) { MixinUtil.addMixins(context); context.setMixInAnnotations(DocumentRequest.class, DocumentRequestMixin.class); - context.setMixInAnnotations(DocumentRequest.DocumentRequestBuilder.class, DocumentRequestMixin.DocumentRequestBuilderMixin.class); + context.setMixInAnnotations(DocumentRequest.DocumentRequestBuilder.class, + DocumentRequestMixin.DocumentRequestBuilderMixin.class); context.setMixInAnnotations(AdmRequest.class, AdmRequestMixin.class); context.setMixInAnnotations(AdmRequest.AdmRequestBuilder.class, AdmRequestMixin.AdmRequestBuilderMixin.class); context.setMixInAnnotations(Name.class, NameMixin.class); context.setMixInAnnotations(Name.NameBuilder.class, NameMixin.NameBuilderMixin.class); context.setMixInAnnotations(NameSimilarityRequest.class, NameSimilarityRequestMixin.class); - context.setMixInAnnotations(NameSimilarityRequest.NameSimilarityRequestBuilder.class, NameSimilarityRequestMixin.NameSimilarityRequestBuilderMixin.class); + context.setMixInAnnotations(NameSimilarityRequest.NameSimilarityRequestBuilder.class, + NameSimilarityRequestMixin.NameSimilarityRequestBuilderMixin.class); context.setMixInAnnotations(NameTranslationRequest.class, NameTranslationRequestMixin.class); - context.setMixInAnnotations(NameTranslationRequest.NameTranslationRequestBuilder.class, NameTranslationRequestMixin.NameTranslationRequestBuilderMixin.class); + context.setMixInAnnotations(NameTranslationRequest.NameTranslationRequestBuilder.class, + NameTranslationRequestMixin.NameTranslationRequestBuilderMixin.class); context.setMixInAnnotations(NameDeduplicationRequest.class, NameDeduplicationRequestMixin.class); - context.setMixInAnnotations(NameDeduplicationRequest.NameDeduplicationRequestBuilder.class, NameDeduplicationRequestMixin.NameDeduplicationRequestBuilderMixin.class); + context.setMixInAnnotations(NameDeduplicationRequest.NameDeduplicationRequestBuilder.class, + NameDeduplicationRequestMixin.NameDeduplicationRequestBuilderMixin.class); + + context.setMixInAnnotations(FieldedAddress.class, FieldedAddressMixin.class); + context.setMixInAnnotations(FieldedAddress.FieldedAddressBuilder.class, + FieldedAddressMixin.FieldedAddressBuilderMixin.class); + context.setMixInAnnotations(UnfieldedAddress.class, UnfieldedAddressMixin.class); + context.setMixInAnnotations(UnfieldedAddress.UnfieldedAddressBuilder.class, + UnfieldedAddressMixin.UnfieldedAddressBuilderMixin.class); + + context.setMixInAnnotations(AddressSimilarityRequest.class, AddressSimilarityRequestMixin.class); + context.setMixInAnnotations(AddressSimilarityRequest.AddressSimilarityRequestBuilder.class, + AddressSimilarityRequestMixin.AddressSimilarityRequestBuilderMixin.class); + context.setMixInAnnotations(ConfigurationRequest.class, ConfigurationRequestMixin.class); + context.setMixInAnnotations(ConfigurationRequest.ConfigurationRequestBuilder.class, + ConfigurationRequestMixin.ConfigurationRequestBuilderMixin.class); + + // IAddresses require a custom deserializer + SimpleDeserializers deserializers = new SimpleDeserializers(); + deserializers.addDeserializer(IAddress.class, new AddressDeserializer()); + deserializers.addDeserializer(NameField.class, new NameFieldDeserializer()); + deserializers.addDeserializer(DateField.class, new DateFieldDeserializer()); + deserializers.addDeserializer(AddressField.class, new AddressFieldDeserializer()); + deserializers.addDeserializer(RecordSimilarityRequest.class, new RecordSimilarityRequestDeserializer()); + deserializers.addDeserializer(RecordSimilarityResponse.class, new RecordSimilarityResponseDeserializer()); + context.addDeserializers(deserializers); } /** diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/ConfigurationRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/ConfigurationRequestMixin.java new file mode 100644 index 000000000..09400fec8 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/ConfigurationRequestMixin.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson; + +import com.basistech.rosette.apimodel.Configuration; +import com.basistech.util.LanguageCode; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +@JsonTypeName("ConfigurationRequest") +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ConfigurationRequestMixin { + @JsonCreator + protected ConfigurationRequestMixin( + @JsonProperty("profileId") String profileId, + @JsonProperty("language") LanguageCode language, + @JsonProperty("configuration") Configuration configuration + ) { + // + } + + @JsonPOJOBuilder(withPrefix = "") + abstract static class ConfigurationRequestBuilderMixin { + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/DocumentRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/DocumentRequestMixin.java index b02541510..5070277d1 100644 --- a/json/src/main/java/com/basistech/rosette/apimodel/jackson/DocumentRequestMixin.java +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/DocumentRequestMixin.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import com.basistech.util.LanguageCode; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; @@ -30,6 +31,7 @@ //CHECKSTYLE:OFF @JsonTypeName("DocumentRequest") +@JsonIgnoreProperties({"genre"}) @JsonInclude(JsonInclude.Include.NON_NULL) public abstract class DocumentRequestMixin { @@ -47,14 +49,13 @@ protected DocumentRequestMixin( @JsonProperty("content") Object content, @JsonProperty("contentUri") String contentUri, @JsonProperty("contentType") String contentType, - @JsonProperty("genre") String genre, @JsonProperty("options") Options options ) { // } @JsonPOJOBuilder(withPrefix = "") - abstract class DocumentRequestBuilderMixin { + abstract static class DocumentRequestBuilderMixin { } @JsonIgnore diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/FieldedAddressMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/FieldedAddressMixin.java new file mode 100644 index 000000000..a288b7918 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/FieldedAddressMixin.java @@ -0,0 +1,54 @@ +/* + * Copyright 2022 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +@JsonTypeName("FieldedAddress") +@JsonInclude(JsonInclude.Include.NON_NULL) +public abstract class FieldedAddressMixin { + + @JsonCreator + protected FieldedAddressMixin(@JsonProperty("house") String house, + @JsonProperty("houseNumber") String houseNumber, + @JsonProperty("road") String road, + @JsonProperty("unit") String unit, + @JsonProperty("level") String level, + @JsonProperty("staircase") String staircase, + @JsonProperty("entrance") String entrance, + @JsonProperty("suburb") String suburb, + @JsonProperty("cityDistrict") String cityDistrict, + @JsonProperty("city") String city, + @JsonProperty("island") String island, + @JsonProperty("stateDistrict") String stateDistrict, + @JsonProperty("state") String state, + @JsonProperty("countryRegion") String countryRegion, + @JsonProperty("country") String country, + @JsonProperty("worldRegion") String worldRegion, + @JsonProperty("postCode") String postCode, + @JsonProperty("poBox") String poBox) { + // + } + + @JsonPOJOBuilder(withPrefix = "") + abstract static class FieldedAddressBuilderMixin { + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameDeduplicationRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameDeduplicationRequestMixin.java index 2afe774e3..0a07ca1f6 100644 --- a/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameDeduplicationRequestMixin.java +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameDeduplicationRequestMixin.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,6 @@ protected NameDeduplicationRequestMixin( } @JsonPOJOBuilder(withPrefix = "") - abstract class NameDeduplicationRequestBuilderMixin { + abstract static class NameDeduplicationRequestBuilderMixin { } } diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameSimilarityRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameSimilarityRequestMixin.java index 45e8a5d58..7dac7d791 100644 --- a/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameSimilarityRequestMixin.java +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameSimilarityRequestMixin.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,10 @@ package com.basistech.rosette.apimodel.jackson; +import java.util.Map; + import com.basistech.rosette.apimodel.Name; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -33,12 +36,13 @@ public abstract class NameSimilarityRequestMixin { protected NameSimilarityRequestMixin( @JsonProperty("profileId") String profileId, @JsonProperty("name1") Name name1, - @JsonProperty("name2") Name name2 - ) { + @JsonProperty("name2") Name name2, + @JsonProperty("parameters") Map parameters + ) { // } @JsonPOJOBuilder(withPrefix = "") - abstract class NameSimilarityRequestBuilderMixin { + abstract static class NameSimilarityRequestBuilderMixin { } } diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameTranslationRequestMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameTranslationRequestMixin.java index 034341d66..90b0976bb 100644 --- a/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameTranslationRequestMixin.java +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/NameTranslationRequestMixin.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,12 +41,13 @@ protected NameTranslationRequestMixin( @JsonProperty("sourceLanguageOfUse") LanguageCode sourceLanguageOfUse, @JsonProperty("targetLanguage") LanguageCode targetLanguage, @JsonProperty("targetScript") ISO15924 targetScript, - @JsonProperty("targetScheme") TransliterationScheme targetScheme + @JsonProperty("targetScheme") TransliterationScheme targetScheme, + @JsonProperty("maximumResults") Integer maximumResults ) { // } @JsonPOJOBuilder(withPrefix = "") - abstract class NameTranslationRequestBuilderMixin { + abstract static class NameTranslationRequestBuilderMixin { } } diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/UnfieldedAddressMixin.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/UnfieldedAddressMixin.java new file mode 100644 index 000000000..2a2bd6223 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/UnfieldedAddressMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +@JsonTypeName("UnfieldedAddress") +@JsonInclude(JsonInclude.Include.NON_NULL) +public abstract class UnfieldedAddressMixin { + + + @JsonCreator + protected UnfieldedAddressMixin(@JsonProperty("address") String address) { + // + } + + @JsonPOJOBuilder(withPrefix = "") + abstract static class UnfieldedAddressBuilderMixin { + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/AddressFieldDeserializer.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/AddressFieldDeserializer.java new file mode 100644 index 000000000..b38c46217 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/AddressFieldDeserializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers; + +import com.basistech.rosette.apimodel.recordsimilarity.records.AddressField; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +public class AddressFieldDeserializer extends StdDeserializer { + public AddressFieldDeserializer() { + super(AddressField.class); + } + + @Override + public AddressField deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + final JsonNode node = jsonParser.getCodec().readTree(jsonParser); + if (node.isObject()) { + return jsonParser.getCodec().treeToValue(node, AddressField.FieldedAddress.class); + } else if (node.isTextual()) { + return AddressField.UnfieldedAddress.builder().address(node.textValue()).build(); + } + throw new IOException("Invalid JSON structure: unexpected node type"); + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/DateFieldDeserializer.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/DateFieldDeserializer.java new file mode 100644 index 000000000..422f34252 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/DateFieldDeserializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers; + +import com.basistech.rosette.apimodel.recordsimilarity.records.DateField; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +public class DateFieldDeserializer extends StdDeserializer { + public DateFieldDeserializer() { + super(DateField.class); + } + + @Override + public DateField deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + final JsonNode node = jsonParser.getCodec().readTree(jsonParser); + if (node.isObject()) { + return jsonParser.getCodec().treeToValue(node, DateField.FieldedDate.class); + } else if (node.isTextual()) { + return DateField.UnfieldedDate.builder().date(node.textValue()).build(); + } + throw new IOException("Invalid JSON structure: unexpected node type"); + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/NameFieldDeserializer.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/NameFieldDeserializer.java new file mode 100644 index 000000000..8fb372bc0 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/NameFieldDeserializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers; + +import com.basistech.rosette.apimodel.recordsimilarity.records.NameField; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +public class NameFieldDeserializer extends StdDeserializer { + public NameFieldDeserializer() { + super(NameField.class); + } + + @Override + public NameField deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + final JsonNode node = jsonParser.getCodec().readTree(jsonParser); + if (node.isObject()) { + return jsonParser.getCodec().treeToValue(node, NameField.FieldedName.class); + } else if (node.isTextual()) { + return NameField.UnfieldedName.builder().text(node.textValue()).build(); + } + throw new IOException("Invalid JSON structure: unexpected node type"); + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityDeserializerUtilities.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityDeserializerUtilities.java new file mode 100644 index 000000000..2618938e8 --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityDeserializerUtilities.java @@ -0,0 +1,154 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityExplainInfo; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityResult; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.JsonNode; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityFieldInfo; +import com.basistech.rosette.apimodel.recordsimilarity.records.AddressField; +import com.basistech.rosette.apimodel.recordsimilarity.records.BooleanField; +import com.basistech.rosette.apimodel.recordsimilarity.records.DateField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NameField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NumberField; +import com.basistech.rosette.apimodel.recordsimilarity.records.RecordFieldType; +import com.basistech.rosette.apimodel.recordsimilarity.records.RecordSimilarityField; +import com.basistech.rosette.apimodel.recordsimilarity.records.StringField; +import com.basistech.rosette.apimodel.recordsimilarity.records.UnknownField; + +final class RecordSimilarityDeserializerUtilities { + + private RecordSimilarityDeserializerUtilities() { + } + + public static RecordSimilarityResult parseResult(JsonNode node, JsonParser jsonParser) throws IOException { + final Double score = node.get("score") != null + ? node.get("score").traverse(jsonParser.getCodec()).readValueAs(Double.class) + : null; + final RecordSimilarityExplainInfo explainInfo = node.get("explainInfo") != null + ? node.get("explainInfo").traverse(jsonParser.getCodec()).readValueAs(RecordSimilarityExplainInfo.class) + : null; + final Map left = node.get("left") != null + ? parseRecordForResponse(node.get("left"), jsonParser) + : null; + final Map right = node.get("right") != null + ? parseRecordForResponse(node.get("right"), jsonParser) + : null; + + List errorList = Optional.ofNullable(node.get("error")) + .map(jsonNode -> StreamSupport.stream(jsonNode.spliterator(), false) + .map(JsonNode::asText) + .collect(Collectors.toList())) + .orElse(null); + final List info = Optional.ofNullable(node.get("info")) + .map(jsonNode -> StreamSupport.stream(jsonNode.spliterator(), false) + .map(JsonNode::asText) + .collect(Collectors.toList())) + .orElse(null); + return RecordSimilarityResult.builder() + .score(score) + .left(left) + .right(right) + .explainInfo(explainInfo) + .error(errorList) + .info(info) + .build(); + } + + static Map parseRecordForResponse(JsonNode jsonNode, JsonParser jsonParser) { + final Map recordMap = new HashMap<>(); + jsonNode.fields().forEachRemaining(entry -> { + String fieldName = entry.getKey(); + try { + recordMap.put(fieldName, jsonNode.get(fieldName).traverse(jsonParser.getCodec()) + .readValueAs(UnknownField.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + return recordMap; + } + + static Map parseRecord( + JsonNode jsonNode, + JsonParser jsonParser, + @NotNull @Valid Map fields + ) throws IOException { + final Iterator> recordsIterator = jsonNode.fields(); + final Map recordMap = new HashMap<>(); + while (recordsIterator.hasNext()) { + final Map.Entry recordEntry = recordsIterator.next(); + final String fieldName = recordEntry.getKey(); + final JsonNode fieldValue = recordEntry.getValue(); + + final RecordSimilarityField fieldData; + + if (fields.containsKey(fieldName)) { + final RecordSimilarityFieldInfo fieldInfo = fields.get(fieldName); + if (fieldInfo.getType() == null) { + throw new IllegalArgumentException("Unspecified field type for: " + fieldName); + } + switch (fieldInfo.getType().toLowerCase(Locale.ENGLISH)) { + case RecordFieldType.RNI_DATE: + fieldData = fieldValue.traverse(jsonParser.getCodec()).readValueAs(DateField.class); + break; + case RecordFieldType.RNI_NAME: + fieldData = fieldValue.traverse(jsonParser.getCodec()).readValueAs(NameField.class); + break; + case RecordFieldType.RNI_ADDRESS: + fieldData = fieldValue.traverse(jsonParser.getCodec()).readValueAs(AddressField.class); + break; + case RecordFieldType.RNI_STRING: + fieldData = StringField.builder().data(fieldValue.textValue()).build(); + break; + case RecordFieldType.RNI_NUMBER: + fieldData = NumberField.builder().data(fieldValue.numberValue()).build(); + break; + case RecordFieldType.RNI_BOOLEAN: + // Be sure not to accidentally convert non-boolean values to 'false' + fieldData = BooleanField.builder() + .data(fieldValue.isBoolean() ? fieldValue.booleanValue() : null) + .build(); + break; + default: + fieldData = fieldValue.traverse(jsonParser.getCodec()).readValueAs(UnknownField.class); + } + } else { + //treat unmapped field as UnknownField so we can get to scoring, + //it won't be counted toward the score anyway + fieldData = fieldValue.traverse(jsonParser.getCodec()).readValueAs(UnknownField.class); + } + recordMap.put(fieldName, fieldData); + } + return recordMap; + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityRequestDeserializer.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityRequestDeserializer.java new file mode 100644 index 000000000..32b0fb6ab --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityRequestDeserializer.java @@ -0,0 +1,74 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityFieldInfo; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityProperties; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRecords; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRequest; +import com.basistech.rosette.apimodel.recordsimilarity.records.RecordSimilarityField; + +public class RecordSimilarityRequestDeserializer extends StdDeserializer { + + public RecordSimilarityRequestDeserializer() { + super(RecordSimilarityRequest.class); + } + + @Override + public RecordSimilarityRequest deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + try (jsonParser) { + final JsonNode node = jsonParser.getCodec().readTree(jsonParser); + final Map fields = node.get("fields") != null ? node.get("fields").traverse(jsonParser.getCodec()).readValueAs(new TypeReference>() { }) : new HashMap<>(); + final RecordSimilarityProperties properties = node.get("properties") != null ? node.get("properties").traverse(jsonParser.getCodec()).readValueAs(RecordSimilarityProperties.class) : RecordSimilarityProperties.builder().build(); + RecordSimilarityRecords records = null; + String recordsField = "records"; + if (node.get(recordsField) != null && fields != null && node.get(recordsField).get("left") != null && node.get(recordsField).get("right") != null) { + records = RecordSimilarityRecords.builder() + .left(parseRecords(node.get(recordsField).get("left"), fields, jsonParser)) + .right(parseRecords(node.get(recordsField).get("right"), fields, jsonParser)) + .build(); + } + return RecordSimilarityRequest.builder() + .fields(fields) + .properties(properties) + .records(records) + .build(); + } + } + + private static List> parseRecords(final JsonNode arrayNode, + final Map fields, + final JsonParser jsonParser) throws IOException { + final List> records = new ArrayList<>(); + for (JsonNode recordNode : arrayNode) { + records.add(RecordSimilarityDeserializerUtilities.parseRecord(recordNode, jsonParser, fields)); + } + return records; + } +} diff --git a/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityResponseDeserializer.java b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityResponseDeserializer.java new file mode 100644 index 000000000..f149f382d --- /dev/null +++ b/json/src/main/java/com/basistech/rosette/apimodel/jackson/recordsimilaritydeserializers/RecordSimilarityResponseDeserializer.java @@ -0,0 +1,63 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel.jackson.recordsimilaritydeserializers; + +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityResponse; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityResult; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class RecordSimilarityResponseDeserializer extends StdDeserializer { + + public RecordSimilarityResponseDeserializer() { + super(RecordSimilarityResponse.class); + } + + @Override + public RecordSimilarityResponse deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + final JsonNode node = jsonParser.getCodec().readTree(jsonParser); + + List info = Optional.ofNullable(node.get("info")) + .map(jsonNode -> StreamSupport.stream(jsonNode.spliterator(), false) + .map(JsonNode::asText) + .collect(Collectors.toList())) + .orElse(null); + String errorMessage = Optional.ofNullable(node.get("errorMessage")).map(JsonNode::asText).orElse(null); + + JsonNode resultsNode = node.get("results"); + List results = new ArrayList<>(); + if (resultsNode != null) { + for (JsonNode resultNode : resultsNode) { + results.add(RecordSimilarityDeserializerUtilities.parseResult(resultNode, jsonParser)); + } + } + return RecordSimilarityResponse.builder() + .results(results) + .info(info) + .errorMessage(errorMessage) + .build(); + } +} diff --git a/json/src/test/data/EntitiesResponse.json b/json/src/test/data/EntitiesResponse.json index 32c1e3a59..de567d958 100644 --- a/json/src/test/data/EntitiesResponse.json +++ b/json/src/test/data/EntitiesResponse.json @@ -15,7 +15,10 @@ "salience": 1.0, "confidence": 1.0, "linkingConfidence": 1.0, - "dbpediaType": "test1" + "dbpediaTypes": [ + "test1", + "test2" + ] } ] } diff --git a/json/src/test/data/InfoResponse.json b/json/src/test/data/InfoResponse.json index 7551c1c61..982af25fe 100644 --- a/json/src/test/data/InfoResponse.json +++ b/json/src/test/data/InfoResponse.json @@ -2,5 +2,6 @@ "buildNumber": "6bafb29d", "buildTime": "2015.05.08_12:31:26", "name": "Rosette API", - "version": "0.5.0" + "version": "0.5.0", + "licenseExpiration": "Nov 19, 2020" } diff --git a/json/src/test/java/com/basistech/rosette/apimodel/EnumTest.java b/json/src/test/java/com/basistech/rosette/apimodel/EnumTest.java index 9d7b8dba3..61e8edb83 100644 --- a/json/src/test/java/com/basistech/rosette/apimodel/EnumTest.java +++ b/json/src/test/java/com/basistech/rosette/apimodel/EnumTest.java @@ -16,24 +16,26 @@ package com.basistech.rosette.apimodel; import com.fasterxml.jackson.core.type.TypeReference; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; import com.fasterxml.jackson.databind.ObjectMapper; import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class EnumTest extends Assert { +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class EnumTest { private ObjectMapper mapper; - @Before + @BeforeEach public void init() { mapper = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); } @Test - public void testCaseInsensitivity() throws Exception { + void testCaseInsensitivity() throws Exception { String json = "{\"content\": \"foo\", \"options\": {\"modelType\": \"dEfAuLT\"}}"; Request request = mapper.readValue(json, new TypeReference>() { }); assertTrue(request instanceof DocumentRequest); diff --git a/json/src/test/java/com/basistech/rosette/apimodel/ModelTest.java b/json/src/test/java/com/basistech/rosette/apimodel/ModelTest.java index 826c38297..03a68eda0 100644 --- a/json/src/test/java/com/basistech/rosette/apimodel/ModelTest.java +++ b/json/src/test/java/com/basistech/rosette/apimodel/ModelTest.java @@ -1,5 +1,5 @@ /* -* Copyright 2017 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,21 @@ package com.basistech.rosette.apimodel; +import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; +import com.basistech.rosette.apimodel.jackson.DocumentRequestMixin; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.reflections.Reflections; +import org.reflections.scanners.SubTypesScanner; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.Constructor; @@ -24,55 +39,36 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Stream; -import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; -import com.basistech.rosette.apimodel.jackson.DocumentRequestMixin; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.reflections.Reflections; -import org.reflections.scanners.SubTypesScanner; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; -@RunWith(Parameterized.class) -public class ModelTest { - - private boolean inputStreams; +@SuppressWarnings("PMD.UnusedPrivateMethod") // Parameterized Tests +class ModelTest { private ObjectMapper mapper; - public ModelTest(Boolean inputStreams) { - this.inputStreams = inputStreams; + private static Stream packageTestParameters() { + return Stream.of( + Arguments.of(true), + Arguments.of(false) + ); } - - @Parameterized.Parameters(name = "inputStreamContent: {0}") - public static Collection data() { - return Arrays.asList(new Object[] {Boolean.FALSE}, new Object[] {Boolean.TRUE}); - } - - - @Before + @BeforeEach public void init() { mapper = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); } - @Test - public void packageTest() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, - InstantiationException, IOException { + @ParameterizedTest(name = "inputStreamContent: {0}") + @MethodSource("packageTestParameters") + void packageTest(boolean inputStreams) throws ClassNotFoundException, IOException { Reflections reflections = new Reflections(this.getClass().getPackage().getName(), new SubTypesScanner(false)); - Set> allClasses = reflections.getSubTypesOf(Object.class); for (Object clazz : allClasses) { String className = ((Class) clazz).getName(); @@ -100,6 +96,16 @@ public void packageTest() throws ClassNotFoundException, IllegalAccessException, continue; } + if (className.contains("ConfigurationRequest")) { + continue; + } + if (className.contains("RecordSimilarityRequest")) { + continue; + } + if (className.contains("UnknownField")) { + continue; + } + Class c = Class.forName(className); if (Modifier.isAbstract(c.getModifiers())) { continue; @@ -120,7 +126,7 @@ public void packageTest() throws ClassNotFoundException, IllegalAccessException, if (className.endsWith("ConstantsResponse")) { inputStreams = false; // special case due to Object in there. } - o1 = createObject(ctor); + o1 = createObject(ctor, inputStreams); } finally { inputStreams = oldInputStreams; } @@ -137,7 +143,6 @@ public void packageTest() throws ClassNotFoundException, IllegalAccessException, o1 = DocumentRequest.builder() .profileId(r.getProfileId()) .language(r.getLanguage()) - .genre(r.getGenre()) .content(r.getContent()) .contentUri(r.getContentUri()) .options(r.getOptions()) @@ -154,7 +159,7 @@ public void packageTest() throws ClassNotFoundException, IllegalAccessException, } - private Object createObject(Constructor ctor) { + private Object createObject(Constructor ctor, boolean inputStreams) { Object o; int argSize = ctor.getParameterTypes().length; Class[] parameterTypes = ctor.getParameterTypes(); @@ -162,7 +167,7 @@ private Object createObject(Constructor ctor) { for (int i = 0; i < argSize; i++) { try { - args[i] = createObjectForType(parameterTypes[i], ctor.getGenericParameterTypes()[i]); + args[i] = createObjectForType(parameterTypes[i], ctor.getGenericParameterTypes()[i], inputStreams); } catch (Throwable e) { e.printStackTrace(); fail(String.format("Unable to create object %s %d %s %s", ctor, i, parameterTypes[i], ctor.getGenericParameterTypes()[i])); @@ -183,8 +188,8 @@ private Object createObject(Constructor ctor) { } //CHECKSTYLE:OFF - private Object createObjectForType(Class type, Type genericParameterType) throws IllegalAccessException, - InstantiationException, InvocationTargetException { + private Object createObjectForType(Class type, Type genericParameterType, boolean inputStreams) + throws IllegalAccessException, InstantiationException, InvocationTargetException { Object o = null; Class firstComponentType = type.isArray() ? type.getComponentType() : type; String typeName = firstComponentType.getSimpleName(); @@ -252,7 +257,7 @@ private Object createObjectForType(Class type, Type genericParameterType) thr case "Collection": case "List": { if (parameterArgClass != null) { - Object o1 = createObjectForType(parameterArgClass, null); + Object o1 = createObjectForType(parameterArgClass, null, inputStreams); List list = new ArrayList<>(); list.add(o1); o = list; @@ -270,7 +275,7 @@ private Object createObjectForType(Class type, Type genericParameterType) thr break; case "Set": { if (parameterArgClass != null) { - Object o1 = createObjectForType(parameterArgClass, null); + Object o1 = createObjectForType(parameterArgClass, null, inputStreams); Set set = new HashSet<>(); set.add(o1); o = set; @@ -289,13 +294,17 @@ private Object createObjectForType(Class type, Type genericParameterType) thr } break; } + case "IAddress": { + o = new UnfieldedAddress("foo"); + break; + } default: if (parameterArgClass != null) { Constructor[] ctors = parameterArgClass.getDeclaredConstructors(); - o = createObject(ctors[0]); + o = createObject(ctors[0], inputStreams); } else { Constructor[] ctors = firstComponentType.getDeclaredConstructors(); - o = createObject(ctors[0]); + o = createObject(ctors[0], inputStreams); } } return o; @@ -376,4 +385,12 @@ private Object createObjectOfType(Type type) { } return object; } + + @Test + void doNotDeserializeGenre() throws JsonProcessingException { + String json = "{\"content\": \"foo\", \"genre\":\"foo\"}"; + // Ensure that the document request no longer deserializes genre + Request request = mapper.readValue(json, new TypeReference>() { }); + assertTrue(mapper.writeValueAsString(request).indexOf("genre") == -1); + } } diff --git a/json/src/test/java/com/basistech/rosette/apimodel/NonNullTest.java b/json/src/test/java/com/basistech/rosette/apimodel/NonNullTest.java index bc397b0b4..fc9b793fa 100644 --- a/json/src/test/java/com/basistech/rosette/apimodel/NonNullTest.java +++ b/json/src/test/java/com/basistech/rosette/apimodel/NonNullTest.java @@ -1,5 +1,5 @@ /* -* Copyright 2014 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,59 +18,50 @@ import java.io.File; import java.io.IOException; -import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; +import java.util.stream.Stream; import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) -public class NonNullTest extends Assert { +import static org.junit.jupiter.api.Assertions.assertFalse; - private final String className; - private final File testFile; +@SuppressWarnings("PMD.UnusedPrivateMethod") // Parameterized Tests +class NonNullTest { private ObjectMapper mapper; - public NonNullTest(String className, File testFile) { - this.className = className; - this.testFile = testFile; - } - // All test resource filename has .json pattern. They contain null requestId and timers fields. - @Parameterized.Parameters(name = "{0}") - public static Collection data() throws URISyntaxException, IOException { + private static Stream testNonNullParameters() throws IOException { File dir = new File("src/test/data"); - Collection params = new ArrayList<>(); + Stream.Builder streamBuilder = Stream.builder(); try (DirectoryStream paths = Files.newDirectoryStream(dir.toPath())) { for (Path file : paths) { if (file.toString().endsWith(".json")) { String className = file.getFileName().toString().replace(".json", ""); - params.add(new Object[]{NonNullTest.class.getPackage().getName() + "." + className, file.toFile()}); + streamBuilder.add(Arguments.of(NonNullTest.class.getPackage().getName() + "." + className, file.toFile())); } } } - return params; + return streamBuilder.build(); } - @Before + @BeforeEach public void init() { mapper = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); } - @Test - public void testNonNull() throws IOException, ClassNotFoundException { + @ParameterizedTest(name = "{0}; {1}") + @MethodSource("testNonNullParameters") + void testNonNull(String className, File testFile) throws IOException, ClassNotFoundException { Class c = Class.forName(className); String s = FileUtils.readFileToString(testFile, StandardCharsets.UTF_8); String s2 = mapper.writeValueAsString(mapper.readValue(s, c)); diff --git a/json/src/test/java/com/basistech/rosette/apimodel/PolymorphicRequestTest.java b/json/src/test/java/com/basistech/rosette/apimodel/PolymorphicRequestTest.java index 20cc831b4..c4cc156d9 100644 --- a/json/src/test/java/com/basistech/rosette/apimodel/PolymorphicRequestTest.java +++ b/json/src/test/java/com/basistech/rosette/apimodel/PolymorphicRequestTest.java @@ -1,5 +1,5 @@ /* -* Copyright 2014 Basis Technology Corp. +* Copyright 2022 Basis Technology Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,47 +15,91 @@ */ package com.basistech.rosette.apimodel; +import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; import com.fasterxml.jackson.core.type.TypeReference; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class PolymorphicRequestTest extends Assert { +class PolymorphicRequestTest { + private static final String DOC_REQUEST = DocumentRequest.class.getName(); private ObjectMapper mapper; - @Before + @BeforeEach public void init() { mapper = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); } @Test - public void testRequestTypes() throws Exception { - String json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"calculateConfidence\": true}}"; + void testRequestTypes() throws Exception { + + String json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"genre\": \"news\"}"; Request request = mapper.readValue(json, new TypeReference>() { }); - assertTrue(request instanceof DocumentRequest); + assertEquals(DOC_REQUEST, request.getClass().getName()); + + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"calculateConfidence\": true}}"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); + + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"includeDBpediaTypes\": true, \"calculateConfidence\": true}}"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); + assertNull(((DocumentRequest) request).getOptions().getIncludePermID()); + + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"includeDBpediaTypes\": true, \"calculateConfidence\": true, \"includePermID\": true}}"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); + assertTrue(((DocumentRequest) request).getOptions().getIncludePermID()); - json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"includeDBpediaType\": true, \"calculateConfidence\": true}}"; + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"includeDBpediaTypes\": true, \"calculateConfidence\": true, \"includePermID\": false}}"; request = mapper.readValue(json, new TypeReference>() { }); - assertTrue(request instanceof DocumentRequest); + assertEquals(DOC_REQUEST, request.getClass().getName()); + assertFalse(((DocumentRequest) request).getOptions().getIncludePermID()); + + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"enableStructuredRegion\": true}}"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); + assertTrue(((DocumentRequest) request).getOptions().getEnableStructuredRegion()); + + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"enableStructuredRegion\": false}}"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); + assertFalse(((DocumentRequest) request).getOptions().getEnableStructuredRegion()); json = "{\"name1\": {\"text\": \"Joe\"}, \"name2\": {\"text\": \"Geo\"}}"; request = mapper.readValue(json, NameSimilarityRequest.class); - assertTrue(request instanceof NameSimilarityRequest); + assertEquals(NameSimilarityRequest.class.getName(), request.getClass().getName()); json = "{\"name\": \"Joe\", \"targetLanguage\": \"ara\"}"; request = mapper.readValue(json, NameTranslationRequest.class); - assertTrue(request instanceof NameTranslationRequest); + assertEquals(NameTranslationRequest.class.getName(), request.getClass().getName()); json = "{\"names\": [{\"text\": \"Joe\"}, {\"text\": \"Smith\"}], \"threshold\": 0.8}"; request = mapper.readValue(json, NameDeduplicationRequest.class); - assertTrue(request instanceof NameDeduplicationRequest); + assertEquals(NameDeduplicationRequest.class.getName(), request.getClass().getName()); json = "{\"names\": [\"Joe\", \"Smith\"], \"threshold\": 0.8}"; request = mapper.readValue(json, NameDeduplicationRequest.class); - assertTrue(request instanceof NameDeduplicationRequest); + assertEquals(NameDeduplicationRequest.class.getName(), request.getClass().getName()); + + json = "{\"language\": \"xxx\", \"configuration\": {\"entities\": { \"LOCATION\": [\"Boston\", \"Mos Eisley\"] } } }"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(ConfigurationRequest.class.getName(), request.getClass().getName()); + } + + @Test + void eventsRequests() throws Exception { + String json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"workspaceId\": \"ws1\"}}"; + Request request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); + + json = "{\"content\": \"what is my type\", \"language\": \"eng\", \"options\": {\"plan\": {\"eng\": [\"abc123\"]}}}"; + request = mapper.readValue(json, new TypeReference>() { }); + assertEquals(DOC_REQUEST, request.getClass().getName()); } } diff --git a/json/src/test/java/com/basistech/rosette/apimodel/RecordSimilarityRequestTest.java b/json/src/test/java/com/basistech/rosette/apimodel/RecordSimilarityRequestTest.java new file mode 100644 index 000000000..254a60998 --- /dev/null +++ b/json/src/test/java/com/basistech/rosette/apimodel/RecordSimilarityRequestTest.java @@ -0,0 +1,247 @@ +/* + * Copyright 2022 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.basistech.rosette.apimodel; + +import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityFieldInfo; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityProperties; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRecords; +import com.basistech.rosette.apimodel.recordsimilarity.RecordSimilarityRequest; +import com.basistech.rosette.apimodel.recordsimilarity.records.AddressField; +import com.basistech.rosette.apimodel.recordsimilarity.records.BooleanField; +import com.basistech.rosette.apimodel.recordsimilarity.records.DateField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NameField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NumberField; +import com.basistech.rosette.apimodel.recordsimilarity.records.RecordFieldType; +import com.basistech.rosette.apimodel.recordsimilarity.records.StringField; +import com.basistech.util.ISO15924; +import com.basistech.util.LanguageCode; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class RecordSimilarityRequestTest { + + private static final ObjectMapper MAPPER = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); + private static final String EXPECTED_JSON = "{\"fields\":{\"num\":{\"type\":\"rni_number\",\"weight\":0.25},\"dob2\":{\"type\":\"rni_date\",\"weight\":0.1},\"bool\":{\"type\":\"rni_boolean\",\"weight\":0.05},\"addr\":{\"type\":\"rni_address\",\"weight\":0.5,\"scoreIfNull\":0.8},\"str\":{\"type\":\"rni_string\",\"weight\":0.8},\"primaryName\":{\"type\":\"rni_name\",\"weight\":0.5},\"dob\":{\"type\":\"rni_date\",\"weight\":0.2}},\"properties\":{\"threshold\":0.7,\"includeExplainInfo\":true},\"records\":{\"left\":[{\"primaryName\":{\"text\":\"Ethan R\",\"entityType\":\"PERSON\",\"language\":\"eng\",\"languageOfOrigin\":\"eng\",\"script\":\"Latn\"},\"num\":42.0,\"dob\":\"1993-04-16\",\"dob2\":{\"date\":\"1993/04/16\",\"format\":\"yyyy/MM/dd\"},\"addr\":\"123 Roadlane Ave\"},{\"primaryName\":{\"text\":\"Evan R\"},\"dob\":{\"date\":\"1993-04-16\"},\"str\":\"some string\",\"bool\":false}],\"right\":[{\"primaryName\":{\"text\":\"Seth R\",\"language\":\"eng\"},\"num\":74301945813095,\"dob\":{\"date\":\"1993-04-16\"},\"bool\":true},{\"addr\":{\"houseNumber\":\"123\",\"road\":\"Roadlane Ave\"},\"str\":\"some other string\",\"dob2\":{\"date\":\"1993/04/16\"},\"primaryName\":\"Ivan R\",\"bool\":true,\"dob\":{\"date\":\"1993-04-16\"}}]}}"; + private static final String EXPECTED_JSON_WITH_PARAMS = "{\"fields\":{\"dob\":{\"type\":\"rni_date\",\"weight\":0.2},\"primaryName\":{\"type\":\"rni_name\",\"weight\":0.5},\"str\":{\"type\":\"rni_string\",\"weight\":0.8},\"addr\":{\"type\":\"rni_address\",\"weight\":0.5},\"bool\":{\"type\":\"rni_boolean\",\"weight\":0.05},\"dob2\":{\"type\":\"rni_date\",\"weight\":0.1},\"num\":{\"type\":\"rni_number\",\"weight\":0.25}},\"properties\":{\"threshold\":0.7,\"includeExplainInfo\":true,\"parameters\":{\"stringDistanceWeight\":\"0.1\",\"timeDistanceWeight\":\"0.8\"}},\"records\":{\"left\":[{\"addr\":\"123 Roadlane Ave\",\"dob2\":{\"date\":\"1993/04/16\"},\"dob\":\"1993-04-16\",\"num\":42.0,\"primaryName\":{\"text\":\"Ethan R\",\"entityType\":\"PERSON\",\"language\":\"eng\",\"languageOfOrigin\":\"eng\",\"script\":\"Latn\"}},{\"dob\":{\"date\":\"1993-04-16\"},\"primaryName\":{\"text\":\"Evan R\"},\"bool\":false,\"str\":\"some string\"}],\"right\":[{\"dob\":{\"date\":\"1993-04-16\"},\"num\":74301945813095,\"primaryName\":{\"text\":\"Seth R\",\"language\":\"eng\"},\"bool\":true},{\"primaryName\":\"Ivan R\",\"dob2\":{\"date\":\"1993/04/16\"},\"str\":\"some other string\",\"addr\":{\"houseNumber\":\"123\",\"road\":\"Roadlane Ave\"},\"dob\":{\"date\":\"1993-04-16\"},\"bool\":true}]}}"; + private static final String EXPECTED_JSON_WITH_UNIVERSE = "{\"fields\":{\"num\":{\"type\":\"rni_number\",\"weight\":0.25},\"primaryName\":{\"type\":\"rni_name\",\"weight\":0.5},\"dob\":{\"type\":\"rni_date\",\"weight\":0.2},\"str\":{\"type\":\"rni_string\",\"weight\":0.8},\"addr\":{\"type\":\"rni_address\",\"weight\":0.5},\"bool\":{\"type\":\"rni_boolean\",\"weight\":0.05},\"dob2\":{\"type\":\"rni_date\",\"weight\":0.1}},\"properties\":{\"threshold\":0.7,\"includeExplainInfo\":true,\"parameterUniverse\":\"myParameterUniverse\"},\"records\":{\"left\":[{\"num\":42.0,\"primaryName\":{\"text\":\"Ethan R\",\"entityType\":\"PERSON\",\"language\":\"eng\",\"languageOfOrigin\":\"eng\",\"script\":\"Latn\"},\"addr\":\"123 Roadlane Ave\",\"dob2\":{\"date\":\"1993/04/16\"},\"dob\":\"1993-04-16\"},{\"primaryName\":{\"text\":\"Evan R\"},\"bool\":false,\"str\":\"some string\",\"dob\":{\"date\":\"1993-04-16\"}}],\"right\":[{\"primaryName\":{\"text\":\"Seth R\",\"language\":\"eng\"},\"bool\":true,\"dob\":{\"date\":\"1993-04-16\"},\"num\":74301945813095},{\"addr\":{\"houseNumber\":\"123\",\"road\":\"Roadlane Ave\"},\"dob\":{\"date\":\"1993-04-16\"},\"bool\":true,\"primaryName\":\"Ivan R\",\"dob2\":{\"date\":\"1993/04/16\"},\"str\":\"some other string\"}]}}"; + + private static final RecordSimilarityRequest EXPECTED_REQUEST = RecordSimilarityRequest.builder() + .fields(Map.of( + "addr", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_ADDRESS).weight(0.5).scoreIfNull(0.8).build(), + "dob2", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.1).scoreIfNull(null).build(), + "primaryName", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NAME).weight(0.5).build(), + "dob", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.2).build(), + "str", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_STRING).weight(0.8).build(), + "num", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NUMBER).weight(0.25).build(), + "bool", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_BOOLEAN).weight(0.05).build())) + .properties(RecordSimilarityProperties.builder().threshold(0.7).includeExplainInfo(true).build()) + .records(RecordSimilarityRecords.builder() + .left( + List.of( + Map.of( + "primaryName", NameField.FieldedName.builder() + .text("Ethan R").entityType("PERSON") + .language(LanguageCode.ENGLISH) + .languageOfOrigin(LanguageCode.ENGLISH) + .script(ISO15924.Latn) + .build(), + "dob", DateField.UnfieldedDate.builder().date("1993-04-16").build(), + "dob2", DateField.FieldedDate.builder().date("1993/04/16").format("yyyy/MM/dd").build(), + "addr", AddressField.UnfieldedAddress.builder().address("123 Roadlane Ave").build(), + "num", NumberField.builder().data(42.0).build() + ), + Map.of( + "primaryName", NameField.FieldedName.builder().text("Evan R").build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "str", StringField.builder().data("some string").build(), + "bool", BooleanField.builder().data(false).build() + ) + ) + ).right( + List.of( + Map.of( + "primaryName", NameField.FieldedName.builder().text("Seth R").language(LanguageCode.ENGLISH).build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "num", NumberField.builder().data(74301945813095L).build(), + "bool", BooleanField.builder().data(true).build() + ), + Map.of( + "primaryName", NameField.UnfieldedName.builder().text("Ivan R").build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "dob2", DateField.FieldedDate.builder().date("1993/04/16").build(), + "addr", AddressField.FieldedAddress.builder().houseNumber("123").road("Roadlane Ave").build(), + "str", StringField.builder().data("some other string").build(), + "bool", BooleanField.builder().data(true).build() + ) + ) + ).build() + ).build(); + + private static final RecordSimilarityRequest EXPECTED_REQUEST_WITH_PARAMS = RecordSimilarityRequest.builder() + .fields(Map.of( + "dob2", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.1).build(), + "primaryName", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NAME).weight(0.5).build(), + "dob", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.2).build(), + "addr", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_ADDRESS).weight(0.5).build(), + "str", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_STRING).weight(0.8).build(), + "num", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NUMBER).weight(0.25).build(), + "bool", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_BOOLEAN).weight(0.05).build())) + .properties(RecordSimilarityProperties.builder() + .threshold(0.7) + .includeExplainInfo(true) + .parameters( + Map.of( + "timeDistanceWeight", "0.8", + "stringDistanceWeight", "0.1" + ) + ) + .build()) + .records(RecordSimilarityRecords.builder() + .left( + List.of( + Map.of( + "primaryName", NameField.FieldedName.builder() + .text("Ethan R").entityType("PERSON") + .language(LanguageCode.ENGLISH) + .languageOfOrigin(LanguageCode.ENGLISH) + .script(ISO15924.Latn) + .build(), + "dob", DateField.UnfieldedDate.builder().date("1993-04-16").build(), + "dob2", DateField.FieldedDate.builder().date("1993/04/16").build(), + "addr", AddressField.UnfieldedAddress.builder().address("123 Roadlane Ave").build(), + "num", NumberField.builder().data(42.0).build() + ), + Map.of( + "primaryName", NameField.FieldedName.builder().text("Evan R").build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "str", StringField.builder().data("some string").build(), + "bool", BooleanField.builder().data(false).build() + ) + ) + ).right( + List.of( + Map.of( + "primaryName", NameField.FieldedName.builder().text("Seth R").language(LanguageCode.ENGLISH).build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "num", NumberField.builder().data(74301945813095L).build(), + "bool", BooleanField.builder().data(true).build() + ), + Map.of( + "primaryName", NameField.UnfieldedName.builder().text("Ivan R").build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "dob2", DateField.FieldedDate.builder().date("1993/04/16").build(), + "addr", AddressField.FieldedAddress.builder().houseNumber("123").road("Roadlane Ave").build(), + "str", StringField.builder().data("some other string").build(), + "bool", BooleanField.builder().data(true).build() + ) + ) + ).build() + ).build(); + + private static final RecordSimilarityRequest EXPECTED_REQUEST_WITH_UNIVERSE = RecordSimilarityRequest.builder() + .fields(Map.of( + "dob", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.2).build(), + "primaryName", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NAME).weight(0.5).build(), + "dob2", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_DATE).weight(0.1).build(), + "addr", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_ADDRESS).weight(0.5).build(), + "str", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_STRING).weight(0.8).build(), + "num", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_NUMBER).weight(0.25).build(), + "bool", RecordSimilarityFieldInfo.builder().type(RecordFieldType.RNI_BOOLEAN).weight(0.05).build())) + .properties(RecordSimilarityProperties.builder() + .threshold(0.7) + .includeExplainInfo(true) + .parameterUniverse("myParameterUniverse") + .build()) + .records(RecordSimilarityRecords.builder() + .left( + List.of( + Map.of( + "primaryName", NameField.FieldedName.builder() + .text("Ethan R").entityType("PERSON") + .language(LanguageCode.ENGLISH) + .languageOfOrigin(LanguageCode.ENGLISH) + .script(ISO15924.Latn) + .build(), + "dob", DateField.UnfieldedDate.builder().date("1993-04-16").build(), + "dob2", DateField.FieldedDate.builder().date("1993/04/16").build(), + "addr", AddressField.UnfieldedAddress.builder().address("123 Roadlane Ave").build(), + "num", NumberField.builder().data(42.0).build() + ), + Map.of( + "primaryName", NameField.FieldedName.builder().text("Evan R").build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "str", StringField.builder().data("some string").build(), + "bool", BooleanField.builder().data(false).build() + ) + ) + ).right( + List.of( + Map.of( + "primaryName", NameField.FieldedName.builder().text("Seth R").language(LanguageCode.ENGLISH).build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "num", NumberField.builder().data(74301945813095L).build(), + "bool", BooleanField.builder().data(true).build() + ), + Map.of( + "primaryName", NameField.UnfieldedName.builder().text("Ivan R").build(), + "dob", DateField.FieldedDate.builder().date("1993-04-16").build(), + "dob2", DateField.FieldedDate.builder().date("1993/04/16").build(), + "addr", AddressField.FieldedAddress.builder().houseNumber("123").road("Roadlane Ave").build(), + "str", StringField.builder().data("some other string").build(), + "bool", BooleanField.builder().data(true).build() + ) + ) + ).build() + ).build(); + + @Test + void testDeserialization() throws JsonProcessingException { + final RecordSimilarityRequest request = MAPPER.readValue(EXPECTED_JSON, new TypeReference<>() { }); + assertEquals(EXPECTED_REQUEST, request); + + final RecordSimilarityRequest requestParams = MAPPER.readValue(EXPECTED_JSON_WITH_PARAMS, new TypeReference<>() { }); + assertEquals(EXPECTED_REQUEST_WITH_PARAMS, requestParams); + + final RecordSimilarityRequest requestUniverse = MAPPER.readValue(EXPECTED_JSON_WITH_UNIVERSE, new TypeReference<>() { }); + assertEquals(EXPECTED_REQUEST_WITH_UNIVERSE, requestUniverse); + } + + @Test + void testSerialization() throws JsonProcessingException { + final JsonNode expectedJson = MAPPER.readTree(EXPECTED_JSON); + final JsonNode actualJson = MAPPER.valueToTree(EXPECTED_REQUEST); + assertEquals(expectedJson, actualJson); + + final JsonNode expectedParamJson = MAPPER.readTree(EXPECTED_JSON_WITH_PARAMS); + final JsonNode actualParamJson = MAPPER.valueToTree(EXPECTED_REQUEST_WITH_PARAMS); + assertEquals(expectedParamJson, actualParamJson); + + final JsonNode expectedUniverseJson = MAPPER.readTree(EXPECTED_JSON_WITH_UNIVERSE); + final JsonNode actualUniverseJson = MAPPER.valueToTree(EXPECTED_REQUEST_WITH_UNIVERSE); + assertEquals(expectedUniverseJson, actualUniverseJson); + } + +} diff --git a/json/src/test/java/com/basistech/rosette/apimodel/recordsimilarity/RecordSimilarityResponseTest.java b/json/src/test/java/com/basistech/rosette/apimodel/recordsimilarity/RecordSimilarityResponseTest.java new file mode 100644 index 000000000..f09b09056 --- /dev/null +++ b/json/src/test/java/com/basistech/rosette/apimodel/recordsimilarity/RecordSimilarityResponseTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2024 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.basistech.rosette.apimodel.recordsimilarity; + + +import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule; +import com.basistech.rosette.apimodel.recordsimilarity.records.AddressField; +import com.basistech.rosette.apimodel.recordsimilarity.records.BooleanField; +import com.basistech.rosette.apimodel.recordsimilarity.records.DateField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NameField; +import com.basistech.rosette.apimodel.recordsimilarity.records.NumberField; +import com.basistech.rosette.apimodel.recordsimilarity.records.StringField; +import com.basistech.util.ISO15924; +import com.basistech.util.LanguageCode; +import com.basistech.util.NEConstants; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class RecordSimilarityResponseTest { + + private static final ObjectMapper MAPPER = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()); + private static final String EXPECTED_JSON = "{\"info\":[\"Field threshold not found in properties! Defaulting to 0.0\",\"Field weight not found in fields! Defaulting to 1.0 for all entries\"],\"results\":[{\"explainInfo\":{\"leftOnlyFields\":[\"addr\"],\"rightOnlyFields\":[\"bool\"],\"scoredFields\":{\"dob\":{\"calculatedWeight\":0.2857142857142857,\"finalScore\":0.74,\"rawScore\":0.8,\"weight\":0.33},\"primaryName\":{\"calculatedWeight\":0.7142857142857143,\"details\":\"any details\",\"finalScore\":0.85,\"rawScore\":0.99,\"weight\":0.33},\"str\":{\"calculatedWeight\":0.0,\"finalScore\":0.5,\"rawScore\":0.5,\"weight\":0.33}}},\"left\":{\"addr\":{\"houseNumber\":\"123\",\"road\":\"Roadlane Ave\"},\"dob\":{\"date\":\"1993-04-16\"},\"num\":2342.15,\"primaryName\":{\"entityType\":\"PERSON\",\"language\":\"eng\",\"languageOfOrigin\":\"eng\",\"script\":\"Latn\",\"text\":\"Ethan R\"},\"str\":\"some string\"},\"right\":{\"bool\":false,\"dob\":\"1993-04-16\",\"primaryName\":{\"text\":\"Seth R\"},\"str\":\"some other string\"},\"score\":0.87},{\"error\":[\"Field foo not found in field mapping\"],\"info\":[\"Some info message\",\"Some other info message\"],\"left\":{\"addr\":{\"houseNumber\":\"123\",\"road\":\"Roadlane Ave\"},\"dob\":{\"date\":\"1993-04-16\"},\"primaryName\":{\"entityType\":\"PERSON\",\"language\":\"eng\",\"languageOfOrigin\":\"eng\",\"script\":\"Latn\",\"text\":\"Ethan R\"}},\"right\":{\"dob\":\"1993-04-16\",\"primaryName\":{\"text\":\"Seth R\"}}}]}"; + + private static final RecordSimilarityResponse EXPECTED_RESPONSE; + + static { + RecordSimilarityResponse temp; + try { + temp = RecordSimilarityResponse.builder() + .results(List.of(RecordSimilarityResult.builder() + .score(0.87) + .left(Map.of("primaryName", NameField.FieldedName.builder() + .text("Ethan R") + .language(LanguageCode.ENGLISH) + .entityType(NEConstants.toString(NEConstants.NE_TYPE_PERSON)) + .languageOfOrigin(LanguageCode.ENGLISH) + .script(ISO15924.Latn) + .build(), + "dob", DateField.FieldedDate.builder() + .date("1993-04-16") + .build(), + "addr", AddressField.FieldedAddress.builder() + .houseNumber("123").road("Roadlane Ave") + .build(), + "str", StringField.builder().data("some string").build(), + "num", NumberField.builder().data(2342.15).build())) + .right(Map.of("primaryName", NameField.FieldedName.builder() + .text("Seth R") + .build(), + "dob", DateField.UnfieldedDate.builder() + .date("1993-04-16") + .build(), + "str", StringField.builder().data("some other string").build(), + "bool", BooleanField.builder().data(false).build())) + .explainInfo(RecordSimilarityExplainInfo.builder() + .leftOnlyFields(List.of("addr")) + .rightOnlyFields(List.of("bool")) + .scoredFields(Map.of("dob", RecordSimilarityFieldExplainInfo.builder() + .weight(0.33) + .calculatedWeight(0.2857142857142857) + .rawScore(0.8) + .finalScore(0.74) + .build(), + "primaryName", + RecordSimilarityFieldExplainInfo.builder() + .weight(0.33) + .calculatedWeight(0.7142857142857143) + .rawScore(0.99) + .finalScore(0.85) + .details(MAPPER.readTree("\"any details\"")) + .build(), + "str", + RecordSimilarityFieldExplainInfo.builder() + .weight(0.33) + .calculatedWeight(0.0) + .rawScore(0.5) + .finalScore(0.5) + .build() + )) + .build()) + .build(), + RecordSimilarityResult.builder() + .left(Map.of("primaryName", NameField.FieldedName.builder() + .text("Ethan R") + .language(LanguageCode.ENGLISH) + .entityType(NEConstants.toString(NEConstants.NE_TYPE_PERSON)) + .languageOfOrigin(LanguageCode.ENGLISH) + .script(ISO15924.Latn) + .build(), + "dob", DateField.FieldedDate.builder() + .date("1993-04-16") + .build(), + "addr", AddressField.FieldedAddress.builder() + .houseNumber("123").road("Roadlane Ave") + .build())) + .right(Map.of("primaryName", NameField.FieldedName.builder() + .text("Seth R") + .build(), + "dob", DateField.UnfieldedDate.builder() + .date("1993-04-16") + .build())) + .error(List.of("Field foo not found in field mapping")) + .info(List.of("Some info message", "Some other info message")) + .build())) + .info(List.of( + "Field threshold not found in properties! Defaulting to 0.0", + "Field weight not found in fields! Defaulting to 1.0 for all entries") + ) + .build(); + } catch (JsonProcessingException e) { + temp = RecordSimilarityResponse.builder().build(); + } + EXPECTED_RESPONSE = temp; + } + + @Test + public void testDeserialization() throws JsonProcessingException { + // For testing, force ordering + MAPPER.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY); + MAPPER.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS); + final RecordSimilarityResponse response = MAPPER.readValue(EXPECTED_JSON, RecordSimilarityResponse.class); + //Can't compare response objects directly since fields within names and other RecordSimilarityField may + // change order, so compare the content of their json strings with fields sorted alphabetically + assertEquals(MAPPER.writeValueAsString(response), MAPPER.writeValueAsString(EXPECTED_RESPONSE)); + } + + @Test + public void testSerialization() throws JsonProcessingException { + // For testing, force ordering + MAPPER.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY); + MAPPER.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS); + assertEquals(EXPECTED_JSON, MAPPER.writeValueAsString(EXPECTED_RESPONSE)); + } +} diff --git a/model/bnd.bnd b/model/bnd.bnd deleted file mode 100644 index c892bd9d3..000000000 --- a/model/bnd.bnd +++ /dev/null @@ -1,2 +0,0 @@ -Bundle-Version: ${osgi-version} -Export-Package: com.basistech.rosette.apimodel,com.basistech.rosette.apimodel.batch diff --git a/model/pom.xml b/model/pom.xml index 26dc42cba..6992e0cfb 100644 --- a/model/pom.xml +++ b/model/pom.xml @@ -1,6 +1,6 @@ - 3.0.0-M1 - 2.4 - 3.10.2 - 1.5 + 3.6.1 + 1.20.0 + 3.1.1 + 1.13.0 + 6.0.1 + 1.18.42 + 1.18.20.0 + 5.15.0 + 0.10.2 annotations @@ -61,34 +58,23 @@ json common api + all examples release - - - - com.basistech - common-api - 36.2.0 - - - com.basistech - adm-model - 2.4.4 - - - com.basistech - adm-json - 2.4.4 - - - + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-pmd-plugin + org.apache.maven.plugins maven-clean-plugin - ${maven-clean-plugin.version} @@ -98,55 +84,20 @@ - false org.apache.maven.plugins maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.7 - 1.7 - 1.7 - - - - com.basistech - bbh-maven-plugin - 1.0.1 - - - osgi-version - validate - - osgi-version - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin.version} - - - attach-javadocs - - jar - - - - - **/target/generated-sources/annotations/com/basistech/rosette/apimodel/** - + 17 + 11 + 11 org.apache.maven.plugins maven-source-plugin - ${maven-source-plugin.version} attach-sources @@ -157,20 +108,6 @@ - - org.apache.maven.plugins - maven-dependency-plugin - - - - set-dep-properties - generate-resources - - properties - - - - org.codehaus.mojo build-helper-maven-plugin @@ -194,13 +131,14 @@ - biz.aQute.bnd - bnd-maven-plugin - ${bnd-maven-plugin.version} + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + attach-javadocs - bnd-process + jar diff --git a/release/pom.xml b/release/pom.xml index bcd30d2a8..7c39985a9 100644 --- a/release/pom.xml +++ b/release/pom.xml @@ -19,7 +19,7 @@ com.basistech.rosette rosette-api-java-binding - 1.11.1-SNAPSHOT + 1.36.1-SNAPSHOT com.basistech.rosette rosette-api-release diff --git a/release/src/scripts/run_all_examples.sh b/release/src/scripts/run_all_examples.sh old mode 100644 new mode 100755 index 8fb39bc71..1fb38168f --- a/release/src/scripts/run_all_examples.sh +++ b/release/src/scripts/run_all_examples.sh @@ -1,34 +1,53 @@ #!/usr/bin/env bash if [ $# -eq 0 ]; then - echo "Usage: $0 API_KEY" 1>&2 + echo "Usage: $0 API_KEY [ALT_URL]" 1>&2 exit 1 fi key=$1 read -d '' examples < - - - Rosette API - - - - org.apache.maven.skins - maven-fluido-skin - ${site-skin-version} - - - - - - - - - - - - - - - - - -