diff --git a/inception/inception-imls-external/pom.xml b/inception/inception-imls-external/pom.xml index 9de05bf4fd3..189304f0b84 100644 --- a/inception/inception-imls-external/pom.xml +++ b/inception/inception-imls-external/pom.xml @@ -104,10 +104,6 @@ com.fasterxml.jackson.core jackson-core - - com.fasterxml.jackson.core - jackson-databind - com.fasterxml.jackson.core jackson-annotations diff --git a/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommender.java b/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommender.java index 8d553e8d731..2963e1febf4 100644 --- a/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommender.java +++ b/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommender.java @@ -27,8 +27,8 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import java.io.IOException; -import java.io.InputStream; import java.io.StringWriter; +import java.lang.invoke.MethodHandles; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; @@ -52,11 +52,8 @@ import org.springframework.http.HttpHeaders; import org.xml.sax.SAXException; -import com.fasterxml.jackson.databind.ObjectMapper; - import de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil; import de.tudarmstadt.ukp.clarin.webanno.api.type.CASMetadata; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.support.JSONUtil; import de.tudarmstadt.ukp.inception.recommendation.api.evaluation.DataSplitter; import de.tudarmstadt.ukp.inception.recommendation.api.evaluation.EvaluationResult; @@ -80,7 +77,7 @@ public class ExternalRecommender { public static final Key KEY_TRAINING_COMPLETE = new Key<>("training_complete"); - private static final Logger LOG = LoggerFactory.getLogger(ExternalRecommender.class); + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final int HTTP_TOO_MANY_REQUESTS = 429; private static final int HTTP_BAD_REQUEST = 400; @@ -96,7 +93,9 @@ public ExternalRecommender(ExternalRecommenderProperties aProperties, Recommende properties = aProperties; traits = aTraits; - client = HttpClient.newBuilder().connectTimeout(properties.getConnectTimeout()).build(); + client = HttpClient.newBuilder() // + .connectTimeout(properties.getConnectTimeout()) // + .build(); } @Override @@ -105,18 +104,18 @@ public boolean isReadyForPrediction(RecommenderContext aContext) if (traits.isTrainable()) { return aContext.get(KEY_TRAINING_COMPLETE).orElse(false); } - else { - return true; - } + + return true; } @Override public void train(RecommenderContext aContext, List aCasses) throws RecommendationException { - TrainingRequest trainingRequest = new TrainingRequest(); + var trainingRequest = new TrainingRequest(); // We assume that the type system for all CAS are the same - String typeSystem = serializeTypeSystem(aCasses.get(0)); + var representativeCas = aCasses.get(0); + var typeSystem = serializeTypeSystem(representativeCas); trainingRequest.setTypeSystem(typeSystem); // Fill in metadata. We use the type system of the first CAS in the list @@ -126,21 +125,22 @@ public void train(RecommenderContext aContext, List aCasses) throws Recomme // of the other CAS. This should happen really rarely, therefore this potential // error is neglected. - trainingRequest.setMetadata(buildMetadata(aCasses.get(0))); + trainingRequest.setMetadata( + buildMetadata(representativeCas, Range.rangeCoveringDocument(representativeCas))); - List documents = new ArrayList<>(); + var documents = new ArrayList(); for (CAS cas : aCasses) { documents.add(buildDocument(cas)); } trainingRequest.setDocuments(documents); - HttpRequest request = HttpRequest.newBuilder() // + var request = HttpRequest.newBuilder() // .uri(URI.create(appendIfMissing(traits.getRemoteUrl(), "/")).resolve("train")) // .header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE) // .timeout(properties.getReadTimeout()) .POST(BodyPublishers.ofString(toJson(trainingRequest), UTF_8)).build(); - HttpResponse response = sendRequest(request); + var response = sendRequest(request); if (response.statusCode() == HTTP_TOO_MANY_REQUESTS) { LOG.info("External recommender is already training"); } @@ -148,8 +148,8 @@ public void train(RecommenderContext aContext, List aCasses) throws Recomme // If the response indicates that the request was not successful, // then it does not make sense to go on and try to decode the XMI else if (response.statusCode() >= HTTP_BAD_REQUEST) { - String responseBody = getResponseBody(response); - String msg = format("Request was not successful: [%d] - [%s]", response.statusCode(), + var responseBody = getResponseBody(response); + var msg = format("Request was not successful: [%d] - [%s]", response.statusCode(), responseBody); throw new RecommendationException(msg); } @@ -161,35 +161,35 @@ else if (response.statusCode() >= HTTP_BAD_REQUEST) { public Range predict(RecommenderContext aContext, CAS aCas, int aBegin, int aEnd) throws RecommendationException { - String typeSystem = serializeTypeSystem(aCas); + var typeSystem = serializeTypeSystem(aCas); - PredictionRequest predictionRequest = new PredictionRequest(); + var predictionRequest = new PredictionRequest(); predictionRequest.setTypeSystem(typeSystem); predictionRequest.setDocument(buildDocument(aCas)); // Fill in metadata - predictionRequest.setMetadata(buildMetadata(aCas)); + predictionRequest.setMetadata(buildMetadata(aCas, new Range(aBegin, aEnd))); - HttpRequest request = HttpRequest.newBuilder() // + var request = HttpRequest.newBuilder() // .uri(URI.create(appendIfMissing(traits.getRemoteUrl(), "/")).resolve("predict")) // .header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE) // .timeout(properties.getReadTimeout()) // .POST(BodyPublishers.ofString(toJson(predictionRequest), UTF_8)) // .build(); - HttpResponse response = sendRequest(request); + var response = sendRequest(request); // If the response indicates that the request was not successful, // then it does not make sense to go on and try to decode the XMI if (response.statusCode() >= HTTP_BAD_REQUEST) { - String responseBody = getResponseBody(response); - String msg = format("Request was not successful: [%d] - [%s]", response.statusCode(), + var responseBody = getResponseBody(response); + var msg = format("Request was not successful: [%d] - [%s]", response.statusCode(), responseBody); throw new RecommendationException(msg); } - PredictionResponse predictionResponse = deserializePredictionResponse(response); + var predictionResponse = deserializePredictionResponse(response); - try (InputStream is = IOUtils.toInputStream(predictionResponse.getDocument(), UTF_8)) { + try (var is = IOUtils.toInputStream(predictionResponse.getDocument(), UTF_8)) { XmiCasDeserializer.deserialize(is, WebAnnoCasUtil.getRealCas(aCas), true); } catch (SAXException | IOException e) { @@ -226,7 +226,7 @@ private String serializeCas(CAS aCas) throws RecommendationException try (var out = new StringWriter()) { // Passing "null" as the type system to the XmiCasSerializer means that we want // to serialize all types (i.e. no filtering for a specific target type system). - XmiCasSerializer xmiCasSerializer = new XmiCasSerializer(null); + var xmiCasSerializer = new XmiCasSerializer(null); var contentHandler = new XMLSerializer(out, true).getContentHandler(); contentHandler = new IllegalXmlCharacterSanitizingContentHandler(contentHandler); xmiCasSerializer.serialize(getRealCas(aCas), contentHandler, null, null, null); @@ -239,10 +239,10 @@ private String serializeCas(CAS aCas) throws RecommendationException private Document buildDocument(CAS aCas) throws RecommendationException { - CASMetadata casMetadata = getCasMetadata(aCas); - String xmi = serializeCas(aCas); - long documentId = casMetadata.getSourceDocumentId(); - String userId = casMetadata.getUsername(); + var casMetadata = getCasMetadata(aCas); + var xmi = serializeCas(aCas); + var documentId = casMetadata.getSourceDocumentId(); + var userId = casMetadata.getUsername(); return new Document(xmi, documentId, userId); } @@ -257,21 +257,20 @@ private CASMetadata getCasMetadata(CAS aCas) throws RecommendationException } } - private Metadata buildMetadata(CAS aCas) throws RecommendationException + private Metadata buildMetadata(CAS aCas, Range aRange) throws RecommendationException { - CASMetadata casMetadata = getCasMetadata(aCas); - AnnotationLayer layer = recommender.getLayer(); + var casMetadata = getCasMetadata(aCas); + var layer = recommender.getLayer(); return new Metadata(layer.getName(), recommender.getFeature().getName(), casMetadata.getProjectId(), layer.getAnchoringMode().getId(), - layer.isCrossSentence()); + layer.isCrossSentence(), aRange); } private PredictionResponse deserializePredictionResponse(HttpResponse response) throws RecommendationException { - ObjectMapper objectMapper = new ObjectMapper(); try { - return objectMapper.readValue(response.body(), PredictionResponse.class); + return JSONUtil.fromJsonString(PredictionResponse.class, response.body()); } catch (IOException e) { throw new RecommendationException("Error while deserializing prediction response!", e); @@ -298,14 +297,13 @@ private HttpResponse sendRequest(HttpRequest aRequest) throws Recommenda } } - private String getResponseBody(HttpResponse response) throws RecommendationException + private String getResponseBody(HttpResponse response) { - if (response.body() != null) { - return response.body(); - } - else { + if (response.body() == null) { return ""; } + + return response.body(); } @Override @@ -317,7 +315,7 @@ public int estimateSampleCount(List aCasses) @Override public EvaluationResult evaluate(List aCasses, DataSplitter aDataSplitter) { - EvaluationResult result = new EvaluationResult(); + var result = new EvaluationResult(); result.setEvaluationSkipped(true); result.setErrorMsg("ExternalRecommender does not support evaluation."); return result; @@ -326,14 +324,12 @@ public EvaluationResult evaluate(List aCasses, DataSplitter aDataSplitter) @Override public TrainingCapability getTrainingCapability() { - if (traits.isTrainable()) { - // - // return TRAINING_SUPPORTED; - // We need to get at least one training CAS because we need to extract the type system - return TRAINING_REQUIRED; - } - else { + if (!traits.isTrainable()) { return TRAINING_NOT_SUPPORTED; } + + // return TRAINING_SUPPORTED; + // We need to get at least one training CAS because we need to extract the type system + return TRAINING_REQUIRED; } } diff --git a/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/model/Metadata.java b/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/model/Metadata.java index 0d06d31056e..dedd7f7ad1e 100644 --- a/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/model/Metadata.java +++ b/inception/inception-imls-external/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/model/Metadata.java @@ -19,9 +19,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import de.tudarmstadt.ukp.inception.rendering.model.Range; + public class Metadata { - + private final Range range; private final String layer; private final String feature; private final long projectId; @@ -32,13 +34,15 @@ public Metadata(@JsonProperty(value = "layer", required = true) String aLayer, @JsonProperty(value = "feature", required = true) String aFeature, @JsonProperty(value = "projectId", required = true) long aProjectId, @JsonProperty(value = "anchoringMode", required = true) String aAnchoringMode, - @JsonProperty(value = "crossSentence", required = true) boolean aCrossSentence) + @JsonProperty(value = "crossSentence", required = true) boolean aCrossSentence, + @JsonProperty(value = "range", required = true) Range aRange) { layer = aLayer; feature = aFeature; projectId = aProjectId; anchoringMode = aAnchoringMode; crossSentence = aCrossSentence; + range = aRange; } public String getLayer() @@ -65,4 +69,9 @@ public boolean isCrossSentence() { return crossSentence; } + + public Range getRange() + { + return range; + } } diff --git a/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommenderIntegrationTest.java b/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommenderIntegrationTest.java index 37217d7a571..ff51b7c146f 100644 --- a/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommenderIntegrationTest.java +++ b/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/ExternalRecommenderIntegrationTest.java @@ -38,7 +38,6 @@ import org.apache.uima.UIMAException; import org.apache.uima.cas.CAS; -import org.apache.uima.collection.CollectionReader; import org.apache.uima.fit.factory.JCasFactory; import org.apache.uima.jcas.JCas; import org.apache.uima.resource.metadata.TypeSystemDescription; @@ -62,7 +61,6 @@ import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.config.ExternalRecommenderPropertiesImpl; import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.messages.PredictionRequest; import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.messages.TrainingRequest; -import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.model.Document; import de.tudarmstadt.ukp.inception.support.test.recommendation.DkproTestHelper; import de.tudarmstadt.ukp.inception.support.test.recommendation.RecommenderTestHelper; import okhttp3.mockwebserver.MockResponse; @@ -85,7 +83,7 @@ public class ExternalRecommenderIntegrationTest private RecommenderContext context; private ExternalRecommender sut; private ExternalRecommenderTraits traits; - private RemoteStringMatchingNerRecommender remoteRecommender; + private MockRemoteStringMatchingNerRecommender remoteRecommender; private MockWebServer server; private List requestBodies; private CasStorageSession casStorageSession; @@ -100,7 +98,7 @@ public void setUp() throws Exception traits = new ExternalRecommenderTraits(); sut = new ExternalRecommender(new ExternalRecommenderPropertiesImpl(), recommender, traits); - remoteRecommender = new RemoteStringMatchingNerRecommender(recommender); + remoteRecommender = new MockRemoteStringMatchingNerRecommender(recommender); server = new MockWebServer(); server.setDispatcher(buildDispatcher()); @@ -122,7 +120,7 @@ public void tearDown() throws Exception @Test public void thatTrainingWorks() throws Exception { - List data = loadDevelopmentData(); + var data = loadDevelopmentData(); assertThatCode(() -> sut.train(context, data)).doesNotThrowAnyException(); } @@ -130,14 +128,14 @@ public void thatTrainingWorks() throws Exception @Test public void thatPredictingWorks() throws Exception { - List casses = loadDevelopmentData(); + var casses = loadDevelopmentData(); sut.train(context, casses); - CAS cas = casses.get(0); + var cas = casses.get(0); RecommenderTestHelper.addScoreFeature(cas, NamedEntity.class, "value"); sut.predict(context, cas); - List predictions = getPredictions(cas, NamedEntity.class); + var predictions = getPredictions(cas, NamedEntity.class); assertThat(predictions).as("Predictions are not empty").isNotEmpty(); @@ -151,22 +149,25 @@ public void thatPredictingWorks() throws Exception @Test public void thatTrainingSendsCorrectRequest() throws Exception { - List casses = loadDevelopmentData(); + var casses = loadDevelopmentData(); sut.train(context, casses); - TrainingRequest request = fromJsonString(TrainingRequest.class, requestBodies.get(0)); + var request = fromJsonString(TrainingRequest.class, requestBodies.get(0)); assertThat(request.getMetadata()) // .hasNoNullFieldsOrProperties() // .hasFieldOrPropertyWithValue("projectId", PROJECT_ID) .hasFieldOrPropertyWithValue("layer", recommender.getLayer().getName()) .hasFieldOrPropertyWithValue("feature", recommender.getFeature().getName()) + .hasFieldOrPropertyWithValue("range.begin", 0) + .hasFieldOrPropertyWithValue("range.end", 263034) .hasFieldOrPropertyWithValue("crossSentence", CROSS_SENTENCE) .hasFieldOrPropertyWithValue("anchoringMode", ANCHORING_MODE.getId()); for (int i = 0; i < request.getDocuments().size(); i++) { - Document doc = request.getDocuments().get(i); - assertThat(doc).hasFieldOrPropertyWithValue("documentId", (long) i) + var doc = request.getDocuments().get(i); + assertThat(doc) // + .hasFieldOrPropertyWithValue("documentId", (long) i) // .hasFieldOrPropertyWithValue("userId", USER_NAME); } } @@ -174,33 +175,38 @@ public void thatTrainingSendsCorrectRequest() throws Exception @Test public void thatPredictingSendsCorrectRequest() throws Exception { - List casses = loadDevelopmentData(); + var casses = loadDevelopmentData(); sut.train(context, casses); - CAS cas = casses.get(0); + + var cas = casses.get(0); RecommenderTestHelper.addScoreFeature(cas, NamedEntity.class, "value"); sut.predict(context, cas); - PredictionRequest request = fromJsonString(PredictionRequest.class, requestBodies.get(1)); + var request = fromJsonString(PredictionRequest.class, requestBodies.get(1)); assertThat(request.getMetadata()) // .hasNoNullFieldsOrProperties() // .hasFieldOrPropertyWithValue("projectId", PROJECT_ID) .hasFieldOrPropertyWithValue("layer", recommender.getLayer().getName()) .hasFieldOrPropertyWithValue("feature", recommender.getFeature().getName()) + .hasFieldOrPropertyWithValue("range.begin", 0) + .hasFieldOrPropertyWithValue("range.end", 263034) .hasFieldOrPropertyWithValue("crossSentence", CROSS_SENTENCE) .hasFieldOrPropertyWithValue("anchoringMode", ANCHORING_MODE.getId()); - assertThat(request.getDocument()).hasFieldOrPropertyWithValue("userId", USER_NAME) + + assertThat(request.getDocument()) // + .hasFieldOrPropertyWithValue("userId", USER_NAME) // .hasFieldOrPropertyWithValue("documentId", 0L); } private List loadDevelopmentData() throws Exception { try { - Dataset ds = loader.load("germeval2014-de", CONTINUE); - List data = loadData(ds, ds.getDefaultSplit().getDevelopmentFiles()); + var ds = loader.load("germeval2014-de", CONTINUE); + var data = loadData(ds, ds.getDefaultSplit().getDevelopmentFiles()); for (int i = 0; i < data.size(); i++) { - CAS cas = data.get(i); + var cas = data.get(i); addCasMetadata(cas.getJCas(), i); casStorageSession.add("testDataCas" + i, EXCLUSIVE_WRITE_ACCESS, cas); } @@ -215,7 +221,7 @@ private List loadDevelopmentData() throws Exception private List loadData(Dataset ds, File... files) throws UIMAException, IOException { - CollectionReader reader = createReader( // + var reader = createReader( // Conll2002Reader.class, // Conll2002Reader.PARAM_PATTERNS, files, // Conll2002Reader.PARAM_LANGUAGE, ds.getLanguage(), // @@ -239,15 +245,15 @@ private List loadData(Dataset ds, File... files) throws UIMAException, IOEx private static Recommender buildRecommender() { - AnnotationLayer layer = new AnnotationLayer(); + var layer = new AnnotationLayer(); layer.setName(TYPE); layer.setCrossSentence(CROSS_SENTENCE); layer.setAnchoringMode(ANCHORING_MODE); - AnnotationFeature feature = new AnnotationFeature(); + var feature = new AnnotationFeature(); feature.setName("value"); - Recommender recommender = new Recommender(); + var recommender = new Recommender(); recommender.setLayer(layer); recommender.setFeature(feature); recommender.setMaxRecommendations(3); @@ -263,7 +269,7 @@ private QueueDispatcher buildDispatcher() public MockResponse dispatch(RecordedRequest request) { try { - String body = request.getBody().readUtf8(); + var body = request.getBody().readUtf8(); requestBodies.add(body); if (Objects.equals(request.getPath(), "/train")) { @@ -271,7 +277,7 @@ public MockResponse dispatch(RecordedRequest request) return new MockResponse().setResponseCode(204); } else if (request.getPath().equals("/predict")) { - String response = remoteRecommender.predict(body); + var response = remoteRecommender.predict(body); return new MockResponse().setResponseCode(200).setBody(response); } } @@ -287,7 +293,7 @@ else if (request.getPath().equals("/predict")) { private void addCasMetadata(JCas aJCas, long aDocumentId) { - CASMetadata cmd = new CASMetadata(aJCas); + var cmd = new CASMetadata(aJCas); cmd.setUsername(USER_NAME); cmd.setProjectId(PROJECT_ID); cmd.setSourceDocumentId(aDocumentId); diff --git a/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/RemoteStringMatchingNerRecommender.java b/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/MockRemoteStringMatchingNerRecommender.java similarity index 66% rename from inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/RemoteStringMatchingNerRecommender.java rename to inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/MockRemoteStringMatchingNerRecommender.java index eedf7986ea7..6b4ecee37dd 100644 --- a/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/RemoteStringMatchingNerRecommender.java +++ b/inception/inception-imls-external/src/test/java/de/tudarmstadt/ukp/inception/recommendation/imls/external/v1/MockRemoteStringMatchingNerRecommender.java @@ -17,13 +17,13 @@ */ package de.tudarmstadt.ukp.inception.recommendation.imls.external.v1; +import static de.tudarmstadt.ukp.clarin.webanno.support.JSONUtil.fromJsonString; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_IS_PREDICTION; import static java.nio.charset.StandardCharsets.UTF_8; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -31,80 +31,61 @@ import org.apache.uima.UIMAException; import org.apache.uima.UIMAFramework; import org.apache.uima.cas.CAS; -import org.apache.uima.cas.Feature; -import org.apache.uima.cas.Type; import org.apache.uima.cas.impl.XmiCasDeserializer; import org.apache.uima.cas.impl.XmiCasSerializer; import org.apache.uima.cas.text.AnnotationFS; import org.apache.uima.fit.factory.JCasFactory; import org.apache.uima.fit.util.CasUtil; -import org.apache.uima.jcas.JCas; -import org.apache.uima.resource.metadata.TypeSystemDescription; import org.apache.uima.util.XMLInputSource; import org.xml.sax.SAXException; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; - +import de.tudarmstadt.ukp.clarin.webanno.support.JSONUtil; import de.tudarmstadt.ukp.inception.recommendation.api.model.Recommender; import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationException; import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommenderContext; import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.messages.PredictionRequest; import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.messages.PredictionResponse; import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.messages.TrainingRequest; -import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.model.Document; import de.tudarmstadt.ukp.inception.recommendation.imls.stringmatch.span.StringMatchingRecommender; import de.tudarmstadt.ukp.inception.recommendation.imls.stringmatch.span.StringMatchingRecommenderTraits; -public class RemoteStringMatchingNerRecommender +public class MockRemoteStringMatchingNerRecommender { private final Recommender recommender; private final RecommenderContext context; private final StringMatchingRecommender recommendationEngine; - public RemoteStringMatchingNerRecommender(Recommender aRecommender) + public MockRemoteStringMatchingNerRecommender(Recommender aRecommender) { recommender = aRecommender; context = new RecommenderContext(); - StringMatchingRecommenderTraits traits = new StringMatchingRecommenderTraits(); + var traits = new StringMatchingRecommenderTraits(); recommendationEngine = new StringMatchingRecommender(recommender, traits); } public void train(String aTrainingRequestJson) throws UIMAException, SAXException, IOException, RecommendationException { - TrainingRequest request = deserializeTrainingRequest(aTrainingRequestJson); + var request = fromJsonString(TrainingRequest.class, aTrainingRequestJson); List casses = new ArrayList<>(); - for (Document doc : request.getDocuments()) { - CAS cas = deserializeCas(doc.getXmi(), request.getTypeSystem()); + for (var doc : request.getDocuments()) { + var cas = deserializeCas(doc.getXmi(), request.getTypeSystem()); casses.add(cas); } recommendationEngine.train(context, casses); } - private TrainingRequest deserializeTrainingRequest(String aRequestJson) - { - try { - ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(aRequestJson, TrainingRequest.class); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - public String predict(String aPredictionRequestJson) throws IOException, UIMAException, SAXException, RecommendationException { - PredictionRequest request = deserializePredictionRequest(aPredictionRequestJson); - CAS cas = deserializeCas(request.getDocument().getXmi(), request.getTypeSystem()); + var request = fromJsonString(PredictionRequest.class, aPredictionRequestJson); + var cas = deserializeCas(request.getDocument().getXmi(), request.getTypeSystem()); // Only work on real annotations, not on predictions - Type predictedType = CasUtil.getType(cas, recommender.getLayer().getName()); - Feature feature = predictedType.getFeatureByBaseName(FEATURE_NAME_IS_PREDICTION); + var predictedType = CasUtil.getType(cas, recommender.getLayer().getName()); + var feature = predictedType.getFeatureByBaseName(FEATURE_NAME_IS_PREDICTION); for (AnnotationFS fs : CasUtil.select(cas, predictedType)) { if (fs.getBooleanValue(feature)) { @@ -117,20 +98,13 @@ public String predict(String aPredictionRequestJson) return buildPredictionResponse(cas); } - private PredictionRequest deserializePredictionRequest(String aPredictionRequestJson) - throws JsonParseException, JsonMappingException, IOException - { - ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(aPredictionRequestJson, PredictionRequest.class); - } - // CAS handling private CAS deserializeCas(String xmi, String typeSystem) throws SAXException, IOException, UIMAException { CAS cas = buildCas(typeSystem); - try (InputStream bais = new ByteArrayInputStream(xmi.getBytes(UTF_8))) { + try (var bais = new ByteArrayInputStream(xmi.getBytes(UTF_8))) { XmiCasDeserializer.deserialize(bais, cas); } return cas; @@ -140,20 +114,18 @@ private CAS buildCas(String typeSystem) throws IOException, UIMAException { // We need to save the typeSystem XML to disk as the // JCasFactory needs a file and not a string - TypeSystemDescription tsd = UIMAFramework.getXMLParser().parseTypeSystemDescription( + var tsd = UIMAFramework.getXMLParser().parseTypeSystemDescription( new XMLInputSource(IOUtils.toInputStream(typeSystem, UTF_8), null)); - JCas jCas = JCasFactory.createJCas(tsd); - return jCas.getCas(); + return JCasFactory.createJCas(tsd).getCas(); } private String buildPredictionResponse(CAS aCas) throws SAXException, IOException { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { XmiCasSerializer.serialize(aCas, null, out, true, null); - PredictionResponse response = new PredictionResponse(); + var response = new PredictionResponse(); response.setDocument(new String(out.toByteArray(), UTF_8)); - ObjectMapper mapper = new ObjectMapper(); - return mapper.writeValueAsString(response); + return JSONUtil.toJsonString(response); } } }