From 307279821d87321ab53a09f8ee6b8db0d5949342 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Mon, 7 Oct 2024 21:24:45 +0200 Subject: [PATCH 1/6] #5085 - Error displaying document when there are no visible layers - Do not exit pre-renderer early when there are no visible layers to avoid leaving the response in an unfinished state - Better handle the case where a document is empty in the brat serializer --- .../api/annotation/rendering/PreRendererImpl.java | 2 +- .../webanno/brat/render/BratSerializerImpl.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/PreRendererImpl.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/PreRendererImpl.java index 35774b75ad0..f58cdfdf2ac 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/PreRendererImpl.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/PreRendererImpl.java @@ -98,7 +98,7 @@ public void render(VDocument aResponse, RenderRequest aRequest) Validate.notNull(cas, "CAS cannot be null"); - if (aRequest.getVisibleLayers().isEmpty() || isEmpty(documentText)) { + if (isEmpty(documentText)) { return; } diff --git a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java index f11fae1f8ef..5106a241ca5 100644 --- a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java +++ b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java @@ -20,6 +20,7 @@ import static de.tudarmstadt.ukp.clarin.webanno.brat.schema.BratSchemaGeneratorImpl.getBratTypeName; import static de.tudarmstadt.ukp.clarin.webanno.model.ScriptDirection.RTL; import static java.util.Arrays.asList; +import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.uima.cas.text.AnnotationPredicates.covering; import static org.apache.uima.cas.text.AnnotationPredicates.overlappingAtBegin; @@ -251,11 +252,11 @@ private static List getArgument(VID aGovernorFs, VID aDependentFs) private void renderText(VDocument aVDoc, GetDocumentResponse aResponse, RenderRequest aRequest) { - if (!aRequest.isIncludeText()) { + if (!aRequest.isIncludeText() || isEmpty(aVDoc.getText())) { return; } - String visibleText = aVDoc.getText(); + var visibleText = aVDoc.getText(); char replacementChar = 0; if (StringUtils.isNotEmpty(properties.getWhiteSpaceReplacementCharacter())) { replacementChar = properties.getWhiteSpaceReplacementCharacter().charAt(0); @@ -267,9 +268,13 @@ private void renderText(VDocument aVDoc, GetDocumentResponse aResponse, RenderRe private void renderBratTokensFromText(GetDocumentResponse aResponse, VDocument aVDoc) { - List bratTokenOffsets = new ArrayList<>(); - String visibleText = aVDoc.getText(); - BreakIterator bi = BreakIterator.getWordInstance(Locale.ROOT); + if (isEmpty(aVDoc.getText())) { + return; + } + + var bratTokenOffsets = new ArrayList(); + var visibleText = aVDoc.getText(); + var bi = BreakIterator.getWordInstance(Locale.ROOT); bi.setText(visibleText); int last = bi.first(); int cur = bi.next(); From bd9581caeeaebf38c9a1334c224ebbb3171e5754 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Tue, 8 Oct 2024 12:41:38 +0200 Subject: [PATCH 2/6] #5087 - Interactive recommender sidebar does not invoke the right recommender - Remove the response limit for Ollama - Distingish different auto-activation reasons in the recommender sidebar - Mark interactive recommender as "active" so that the PredictionTask considers them (not yet sure if that is the best approach, but then at least also the "accept best" buttons in the recommender sidebar are there) - Skip interactive recommenders unless they are explicitly included to be run in a PredictionTask - Log a bit more timing information --- .../imls/ollama/OllamaRecommender.java | 7 +- .../api/model/EvaluatedRecommender.java | 12 +++- .../service/RecommendationServiceImpl.java | 6 +- ...NonTrainableRecommenderActivationTask.java | 9 ++- .../recommendation/tasks/PredictionTask.java | 71 +++++++++++++------ .../recommendation/tasks/SelectionTask.java | 31 ++++---- 6 files changed, 88 insertions(+), 48 deletions(-) diff --git a/inception/inception-imls-ollama/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/ollama/OllamaRecommender.java b/inception/inception-imls-ollama/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/ollama/OllamaRecommender.java index dd2264971dc..8770d8f6d27 100644 --- a/inception/inception-imls-ollama/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/ollama/OllamaRecommender.java +++ b/inception/inception-imls-ollama/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/ollama/OllamaRecommender.java @@ -20,6 +20,7 @@ import static de.tudarmstadt.ukp.inception.recommendation.imls.support.llm.prompt.PromptContextGenerator.VAR_EXAMPLES; import static de.tudarmstadt.ukp.inception.recommendation.imls.support.llm.prompt.PromptContextGenerator.getPromptContextGenerator; import static de.tudarmstadt.ukp.inception.recommendation.imls.support.llm.response.ResponseExtractor.getResponseExtractor; +import static java.lang.System.currentTimeMillis; import java.io.IOException; import java.lang.invoke.MethodHandles; @@ -99,11 +100,11 @@ private String query(String aPrompt) throws IOException .withFormat(traits.getFormat()) // .withRaw(traits.isRaw()) // .withStream(false) // - // FIXME: Make NUM_PREDICT accessible in UI - .withOption(OllamaGenerateRequest.NUM_PREDICT, 300) // .build(); + var startTime = currentTimeMillis(); var response = client.generate(traits.getUrl(), request).trim(); - LOG.trace("Ollama [{}] responds: [{}]", traits.getModel(), response); + LOG.trace("Ollama [{}] responds ({} ms): [{}]", traits.getModel(), + currentTimeMillis() - startTime, response); return response; } } diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/EvaluatedRecommender.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/EvaluatedRecommender.java index 575b17e539c..90973e15f53 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/EvaluatedRecommender.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/EvaluatedRecommender.java @@ -56,10 +56,16 @@ public String getReasonForState() return reasonForState; } - public static EvaluatedRecommender makeActiveWithoutEvaluation(Recommender aRecommender) + @Override + public String toString() { - return new EvaluatedRecommender(aRecommender, EvaluationResult.skipped(), true, - "Recommender is always active (without evaluation)."); + return "EvaluatedRecommender [" + recommender + " -> " + (active ? "ACTIVE" : "OFF") + "]"; + } + + public static EvaluatedRecommender makeActiveWithoutEvaluation(Recommender aRecommender, + String aReason) + { + return new EvaluatedRecommender(aRecommender, EvaluationResult.skipped(), true, aReason); } public static EvaluatedRecommender makeActive(Recommender aRecommender, diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java index 4270915d8a3..4503ed2f02a 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java @@ -43,7 +43,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.collections4.MapIterator; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.multimap.HashSetValuedHashMap; import org.apache.commons.lang3.Validate; @@ -1406,10 +1405,9 @@ public void setPreferences(Preferences aPreferences) public MultiValuedMap getActiveRecommenders() { - MultiValuedMap active = new HashSetValuedHashMap<>(); + var active = new HashSetValuedHashMap(); - MapIterator i = evaluatedRecommenders - .mapIterator(); + var i = evaluatedRecommenders.mapIterator(); while (i.hasNext()) { i.next(); if (i.getValue().isActive()) { diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/NonTrainableRecommenderActivationTask.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/NonTrainableRecommenderActivationTask.java index 4464773aa18..a76bb974187 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/NonTrainableRecommenderActivationTask.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/NonTrainableRecommenderActivationTask.java @@ -146,6 +146,10 @@ private Optional considerRecommender(User user, Recommende var engine = factory.build(recommender); + if (factory.isInteractive(recommender)) { + return Optional.of(activateNonTrainableRecommender(user, recommender, engine)); + } + return switch (engine.getTrainingCapability()) { case TRAINING_NOT_SUPPORTED, TRAINING_SUPPORTED -> Optional .of(activateNonTrainableRecommender(user, recommender, engine)); @@ -169,7 +173,8 @@ private EvaluatedRecommender activateNonTrainableRecommender(User user, Recommen LOG.debug("[{}][{}]: Activating [{}] non-trainable recommender", user.getUsername(), recommenderName, recommenderName); info("Recommender [%s] activated because it is not trainable", recommenderName); - return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender); + return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender, + "Non-trainable recommenders is always active (without evaluation)"); } private EvaluatedRecommender skipTrainableRecommender(User user, Recommender recommender) @@ -237,8 +242,6 @@ public static Builder> builder() public static class Builder> extends RecommendationTask_ImplBase.Builder { - private Recommender recommender; - public NonTrainableRecommenderActivationTask build() { return new NonTrainableRecommenderActivationTask(this); diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/PredictionTask.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/PredictionTask.java index c301691ed44..30a33769879 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/PredictionTask.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/PredictionTask.java @@ -66,7 +66,6 @@ import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommenderContext; import de.tudarmstadt.ukp.inception.recommendation.event.RecommenderTaskNotificationEvent; import de.tudarmstadt.ukp.inception.rendering.model.Range; -import de.tudarmstadt.ukp.inception.scheduling.TaskMonitor; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.StopWatch; import de.tudarmstadt.ukp.inception.support.WebAnnoConst; @@ -196,7 +195,7 @@ private Predictions generatePredictions() } } - return generatePredictionsOnSingleDocument(currentDocument, docs, getMonitor()); + return generatePredictionsOnSingleDocument(currentDocument, docs); } /** @@ -255,7 +254,7 @@ private Predictions generatePredictionsOnAllDocuments(List aDocu * @return the new predictions. */ private Predictions generatePredictionsOnSingleDocument(SourceDocument aCurrentDocument, - List aDocuments, TaskMonitor aMonitor) + List aDocuments) { var sessionOwner = getSessionOwner(); var project = getProject(); @@ -264,7 +263,7 @@ private Predictions generatePredictionsOnSingleDocument(SourceDocument aCurrentD ? new Predictions(predecessorPredictions) : new Predictions(sessionOwner, dataOwner, project); - aMonitor.setMaxProgress(1); + getMonitor().setMaxProgress(1); if (predecessorPredictions != null) { // Limit prediction to a single document and inherit the rest @@ -308,7 +307,7 @@ private Predictions generatePredictionsOnSingleDocument(SourceDocument aCurrentD logErrorCreationPredictionCas(incomingPredictions); } - aMonitor.setProgress(1); + getMonitor().setProgress(1); return incomingPredictions; } @@ -354,15 +353,22 @@ private void applyActiveRecommendersToDocument(Predictions aActivePredictions, try { var originalCas = new LazyCas(aDocument); for (var activeRecommender : activeRecommenders) { - // Make sure we have the latest recommender config from the DB - the one - // from the active recommenders list may be outdated var rec = activeRecommender.getRecommender(); - try { - rec = recommendationService.getRecommender(rec.getId()); + // If a recommender is explicitly requested, the configuration from the requested + // recommender object takes precedence over what is stored in the database + if (!recommenders.isEmpty() && recommenders.contains(rec)) { + rec = recommenders.get(recommenders.indexOf(rec)); } - catch (NoResultException e) { - logRecommenderNotAvailable(aPredictions, rec); - continue; + else { + // Make sure we have the latest recommender config from the DB - the one + // from the active recommenders list may be outdated + try { + rec = recommendationService.getRecommender(rec.getId()); + } + catch (NoResultException e) { + logRecommenderNotAvailable(aPredictions, rec); + continue; + } } applySingleRecomenderToDocument(originalCas, rec, aActivePredictions, aPredictions, @@ -425,6 +431,17 @@ private void applySingleRecomenderToDocument(LazyCas aOriginalCas, Recommender a return; } + if (recommenders.isEmpty() && factory.isInteractive(aRecommender)) { + logSkippingInteractiveRecommenderNotExplicitlyRequested(aPredictions, aRecommender); + + if (activePredictions != null) { + inheritSuggestionsAtRecommenderLevel(aPredictions, aRecommender, activePredictions, + aDocument); + } + + return; + } + var engine = factory.build(aRecommender); var isSynchronous = factory.isSynchronous(aRecommender); @@ -467,9 +484,11 @@ private void applySingleRecomenderToDocument(LazyCas aOriginalCas, Recommender a return; } - // If the recommender is not trainable and not sensitive to annotations, we can actually + // If the recommender is not trainable and not sensitive to user input/annotations, we can + // actually // re-use the predictions. - if (TRAINING_NOT_SUPPORTED == engine.getTrainingCapability() + if (!factory.isInteractive(aRecommender) + && TRAINING_NOT_SUPPORTED == engine.getTrainingCapability() && PREDICTION_USES_TEXT_ONLY == engine.getPredictionCapability() && activePredictions != null && activePredictions.hasRunPredictionOnDocument(aDocument)) { @@ -536,6 +555,7 @@ private void invokeRecommender(Predictions aIncomingPredictions, PredictionConte var suggestionSupport = maybeSuggestionSupport.get(); // Perform the actual prediction + var startTime = System.currentTimeMillis(); var predictedRange = predict(aIncomingPredictions, aCtx, aEngine, aPredictionCas, aPredictionRange); @@ -547,7 +567,7 @@ private void invokeRecommender(Predictions aIncomingPredictions, PredictionConte generatedSuggestions); logGeneratedPredictions(aIncomingPredictions, aDocument, rec, predictedRange, - generatedSuggestions, reconciliationResult); + generatedSuggestions, reconciliationResult, currentTimeMillis() - startTime); // Inherit suggestions that are outside the range which was predicted. Note that the engine // might actually predict a different range from what was requested. If the prediction @@ -837,17 +857,17 @@ private void logPredictionStartedForAllDocuments(List docs) private void logGeneratedPredictions(Predictions aIncomingPredictions, SourceDocument aDocument, Recommender aRecommender, Range predictedRange, List generatedSuggestions, - ReconciliationResult reconciliationResult) + ReconciliationResult reconciliationResult, long aDuration) { LOG.debug( - "{} for user {} on document {} in project {} generated {} predictions within range {} (+{}/-{}/={})", + "{} for user {} on document {} in project {} generated {} predictions within range {} (+{}/-{}/={}) ({} ms)", aRecommender, getSessionOwner(), aDocument, aRecommender.getProject(), generatedSuggestions.size(), predictedRange, reconciliationResult.added, - reconciliationResult.removed, reconciliationResult.aged); + reconciliationResult.removed, reconciliationResult.aged, aDuration); aIncomingPredictions.log(LogMessage.info(aRecommender.getName(), // - "Generated [%d] predictions within range %s (+%d/-%d/=%d)", + "Generated [%d] predictions within range %s (+%d/-%d/=%d) (%d ms)", generatedSuggestions.size(), predictedRange, reconciliationResult.added, - reconciliationResult.removed, reconciliationResult.aged)); + reconciliationResult.removed, reconciliationResult.aged, aDuration)); } private void logRecommenderContextNoReady(Predictions aPredictions, SourceDocument aDocument, @@ -869,6 +889,17 @@ private void logSkippingNotRequestedRecommender(Predictions aPredictions, getSessionOwner().getUsername(), aRecommender.getName()); } + private void logSkippingInteractiveRecommenderNotExplicitlyRequested(Predictions aPredictions, + Recommender aRecommender) + { + aPredictions.log(LogMessage.info(aRecommender.getName(), + "Interactive recommender not requested for this run... skipping")); + LOG.info( + "[{}][{}]: Interactive recommender not requested for this run " + + "- skipping recommender", + getSessionOwner().getUsername(), aRecommender.getName()); + } + private void logSkippingSynchronous(Predictions aPredictions, Recommender aRecommender) { aPredictions.log(LogMessage.info(aRecommender.getName(), diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/SelectionTask.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/SelectionTask.java index 73bc6f440a4..909978f7f88 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/SelectionTask.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/tasks/SelectionTask.java @@ -148,7 +148,7 @@ protected List initialize() seenRecommender = true; } - Recommender recommender = optRecommender.get(); + var recommender = optRecommender.get(); try { long start = System.currentTimeMillis(); @@ -281,7 +281,7 @@ private Optional evaluate(User user, Recommender recommend } if (factory.isInteractive(recommender)) { - return Optional.of(skipInteractiveRecommender(user, recommender)); + return Optional.of(activateInteractiveRecommender(user, recommender)); } if (recommender.isAlwaysSelected()) { @@ -359,31 +359,32 @@ private EvaluatedRecommender activateNonEvaluatableRecommender(String userName, Recommender recommender) { String recommenderName = recommender.getName(); - LOG.debug("[{}][{}]: Activating [{}] without evaluating - not evaluable", userName, + LOG.debug("[{}][{}]: Activating [{}] without evaluation - not evaluable", userName, recommenderName, recommenderName); - info("Recommender [%s] activated without evaluating - not evaluable", recommenderName); - return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender); + info("Recommender [%s] activated without evaluation - not evaluable", recommenderName); + return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender, + "Non-evaluatable recommender is always active (without evaluation)."); } private EvaluatedRecommender activateAlwaysOnRecommender(String userName, Recommender recommender) { String recommenderName = recommender.getName(); - LOG.debug("[{}][{}]: Activating [{}] without evaluating - always selected", userName, + LOG.debug("[{}][{}]: Activating [{}] without evaluation - always selected", userName, recommenderName, recommenderName); - info("Recommender [%s] activated without evaluating - always selected", recommenderName); - return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender); + info("Recommender [%s] activated without evaluation - always selected", recommenderName); + return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender, + "Recommender is always active (without evaluation)."); } - private EvaluatedRecommender skipInteractiveRecommender(User user, Recommender recommender) + private EvaluatedRecommender activateInteractiveRecommender(User user, Recommender recommender) { var recommenderName = recommender.getName(); - LOG.info("[{}][{}]: Recommender reserved for interactive use " + "- skipping recommender", - user.getUsername(), recommenderName); - info("Recommender [%s] reserved for interactive use - skipping recommender", - recommenderName); - return EvaluatedRecommender.makeInactiveWithoutEvaluation(recommender, - "Reserved for interactive use"); + LOG.info("[{}][{}]: Activating [{}] without evaluation - interactive use", + user.getUsername(), recommenderName, recommenderName); + info("Recommender [%s] without evaluation - interactive use", recommenderName); + return EvaluatedRecommender.makeActiveWithoutEvaluation(recommender, + "Interactive recommender is always active (without evaluation)."); } private EvaluatedRecommender skipRecommenderWithInvalidSettings(User user, From ec55e2b8f1d93b72a2ca4dc75f9eaa2eca01d9c9 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Sun, 13 Oct 2024 21:14:09 +0200 Subject: [PATCH 3/6] #5089 - Document structure is not retained when preparing a document as curation target - Transfer document structure when preparing the curation CAS --- .../inception/curation/merge/CasMerge.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java b/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java index 63fb7e10a4b..6b7132f51bd 100644 --- a/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java +++ b/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java @@ -41,6 +41,10 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.FeatureStructure; import org.apache.uima.cas.text.AnnotationFS; +import org.apache.uima.util.CasCopier; +import org.dkpro.core.api.xml.type.XmlAttribute; +import org.dkpro.core.api.xml.type.XmlDocument; +import org.dkpro.core.api.xml.type.XmlNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; @@ -412,25 +416,40 @@ private void clearAnnotations(SourceDocument aDocument, CAS aCas) throws UIMAExc aCas.setDocumentText(backup.getDocumentText()); transferSegmentation(aDocument.getProject(), aCas, backup); + transferDocumentStructure(aDocument.getProject(), aCas, backup); + } + + private void transferDocumentStructure(Project aProject, CAS aTarget, CAS aSource) + { + var casCopier = new CasCopier(aSource, aTarget); + // Recursively copy the structure - this does not add the copied annotations to the index + for (var doc : aSource.select(XmlDocument.class)) { + casCopier.copyFs(doc); + } + + // Add the document structure annotations to the index + aTarget.select(XmlDocument.class).forEach(aTarget::addFsToIndexes); + aTarget.select(XmlNode.class).forEach(aTarget::addFsToIndexes); + aTarget.select(XmlAttribute.class).forEach(aTarget::addFsToIndexes); } /** * If tokens and/or sentences are not editable, then they are not part of the curation process * and we transfer them from the template CAS. */ - private void transferSegmentation(Project aProject, CAS aCas, CAS backup) + private void transferSegmentation(Project aProject, CAS aTarget, CAS aSource) { if (!schemaService.isTokenLayerEditable(aProject)) { // Transfer token boundaries - for (var t : selectTokens(backup)) { - aCas.addFsToIndexes(createToken(aCas, t.getBegin(), t.getEnd())); + for (var t : selectTokens(aSource)) { + aTarget.addFsToIndexes(createToken(aTarget, t.getBegin(), t.getEnd())); } } if (!schemaService.isSentenceLayerEditable(aProject)) { // Transfer sentence boundaries - for (var s : selectSentences(backup)) { - aCas.addFsToIndexes(createSentence(aCas, s.getBegin(), s.getEnd())); + for (var s : selectSentences(aSource)) { + aTarget.addFsToIndexes(createSentence(aTarget, s.getBegin(), s.getEnd())); } } } From 7668a097a21a186cfc7623738935049ad56db0b0 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Mon, 14 Oct 2024 20:36:57 +0200 Subject: [PATCH 4/6] #5089 - Document structure is not retained when preparing a document as curation target - Transfer document structure when preparing the curation CAS - Offer check for missing document structure in curation CAS - Offer repair for missing document structure in curation CAS --- .../casstorage/CasStorageServiceAction.java | 4 +- .../storage/CasStorageServiceImpl.java | 116 +++++++----------- inception/inception-curation/pom.xml | 4 + .../inception/curation/merge/CasMerge.java | 21 +--- inception/inception-diag/pom.xml | 8 ++ .../ukp/clarin/webanno/diag/CasDoctor.java | 59 ++++----- ...tationsStartAndEndWithCharactersCheck.java | 7 +- ...ationsStartAndEndWithinSentencesCheck.java | 13 +- .../AllFeatureStructuresIndexedCheck.java | 5 +- .../checks/CASMetadataTypeIsPresentCheck.java | 5 +- .../ukp/clarin/webanno/diag/checks/Check.java | 5 +- .../diag/checks/DanglingRelationsCheck.java | 25 ++-- .../DocumentTextStartsWithBomCheck.java | 5 +- ...chedSpanAnnotationsTrulyAttachedCheck.java | 11 +- .../LinksReachableThroughChainsCheck.java | 13 +- .../checks/NegativeSizeAnnotationsCheck.java | 5 +- .../NoMultipleIncomingRelationsCheck.java | 20 ++- .../NoZeroSizeTokensAndSentencesCheck.java | 5 +- .../diag/checks/RelationOffsetsCheck.java | 13 +- ...okensAndSententencedDoNotOverlapCheck.java | 5 +- .../checks/UniqueDocumentAnnotationCheck.java | 5 +- .../checks/UnreachableAnnotationsCheck.java | 5 +- ...XmlStructurePresentInCurationCasCheck.java | 78 ++++++++++++ .../config/CasDoctorAutoConfiguration.java | 17 +++ .../CoverAllTextInSentencesRepair.java | 5 +- ...dSpanAnnotationsAndDeleteExtrasRepair.java | 35 +++--- ...hFeatureAttachedSpanAnnotationsRepair.java | 23 ++-- ...xFeatureAttachedSpanAnnotationsRepair.java | 15 ++- .../diag/repairs/RelationOffsetsRepair.java | 15 ++- .../webanno/diag/repairs/RemoveBomRepair.java | 5 +- .../RemoveDanglingChainLinksRepair.java | 7 +- ...gFeatureAttachedSpanAnnotationsRepair.java | 7 +- .../RemoveDanglingRelationsRepair.java | 7 +- ...emoveZeroSizeTokensAndSentencesRepair.java | 5 +- .../clarin/webanno/diag/repairs/Repair.java | 4 +- ...eplaceXmlStructureInCurationCasRepair.java | 81 ++++++++++++ ...ndEndOnNegativeSizedAnnotationsRepair.java | 5 +- .../diag/repairs/TrimAnnotationsRepair.java | 7 +- .../diag/repairs/UpgradeCasRepair.java | 7 +- .../asciidoc/user-guide/casdoctor.adoc | 48 +++++--- .../AllAnnotationsIndexedCheckTest.java | 4 +- ...onsStartAndEndWithCharactersCheckTest.java | 10 +- ...nsStartAndEndWithinSentencesCheckTest.java | 12 +- .../NegativeSizeAnnotationsCheckTest.java | 9 +- .../NoMultipleIncomingRelationsCheckTest.java | 98 ++++++++------- ...sAndSententencedDoNotOverlapCheckTest.java | 11 +- .../CoverAllTextInSentencesRepairTest.java | 15 +-- .../diag/repairs/RemoveBomRepairTest.java | 2 +- .../RemoveDanglingRelationsRepairTest.java | 20 ++- ...dOnNegativeSizedAnnotationsRepairTest.java | 5 +- .../DocumentImportExportServiceImpl.java | 9 +- .../io/xml/dkprocore/XmlNodeUtils.java | 39 +++++- .../ui/project/casdoctor/CheckTask.java | 9 +- .../ui/project/casdoctor/RepairTask.java | 9 +- 54 files changed, 613 insertions(+), 369 deletions(-) create mode 100644 inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/XmlStructurePresentInCurationCasCheck.java create mode 100644 inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReplaceXmlStructureInCurationCasRepair.java diff --git a/inception/inception-annotation-storage-api/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/casstorage/CasStorageServiceAction.java b/inception/inception-annotation-storage-api/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/casstorage/CasStorageServiceAction.java index 4bdeb97f06a..a6131b491f0 100644 --- a/inception/inception-annotation-storage-api/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/casstorage/CasStorageServiceAction.java +++ b/inception/inception-annotation-storage-api/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/casstorage/CasStorageServiceAction.java @@ -19,8 +19,10 @@ import org.apache.uima.cas.CAS; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; + @FunctionalInterface public interface CasStorageServiceAction { - void apply(CAS aCas) throws Exception; + void apply(SourceDocument aDocument, String aDataOwner, CAS aCas) throws Exception; } diff --git a/inception/inception-annotation-storage/src/main/java/de/tudarmstadt/ukp/inception/annotation/storage/CasStorageServiceImpl.java b/inception/inception-annotation-storage/src/main/java/de/tudarmstadt/ukp/inception/annotation/storage/CasStorageServiceImpl.java index 91abb9b388c..da6d93314a2 100644 --- a/inception/inception-annotation-storage/src/main/java/de/tudarmstadt/ukp/inception/annotation/storage/CasStorageServiceImpl.java +++ b/inception/inception-annotation-storage/src/main/java/de/tudarmstadt/ukp/inception/annotation/storage/CasStorageServiceImpl.java @@ -76,7 +76,6 @@ import de.tudarmstadt.ukp.clarin.webanno.api.casstorage.ConcurentCasModificationException; import de.tudarmstadt.ukp.clarin.webanno.diag.CasDoctor; import de.tudarmstadt.ukp.clarin.webanno.diag.CasDoctorException; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.storage.config.CasStorageCacheProperties; import de.tudarmstadt.ukp.inception.annotation.storage.config.CasStorageServiceAutoConfiguration; @@ -679,34 +678,11 @@ public boolean deleteCas(SourceDocument aDocument, String aUsername) } @Override - public void analyzeAndRepair(SourceDocument aDocument, String aUsername, CAS aCas) + public void analyzeAndRepair(SourceDocument aDocument, String aDataOwner, CAS aCas) { - analyzeAndRepair(aDocument.getProject(), aDocument.getName(), aDocument.getId(), aUsername, - aCas); - } + var project = aDocument.getProject(); - /** - * Runs {@link CasDoctor} in repair mode on the given CAS (if repairs are active), otherwise it - * runs only in analysis mode. - *

- * Note: {@link CasDoctor} is an optional service. If no {@link CasDoctor} implementation - * is available, this method returns without doing anything. - * - * @param aProject - * the project - * @param aDocumentName - * the document name (used for logging) - * @param aDocumentId - * the aDocument ID (used for logging) - * @param aUsername - * the user owning the CAS (used for logging) - * @param aCas - * the CAS object - */ - private void analyzeAndRepair(Project aProject, String aDocumentName, long aDocumentId, - String aUsername, CAS aCas) - { - try (var logCtx = withProjectLogger(aProject)) { + try (var logCtx = withProjectLogger(project)) { if (casDoctor == null) { return; } @@ -715,18 +691,18 @@ private void analyzeAndRepair(Project aProject, String aDocumentName, long aDocu // because the repairs do an analysis as a pre- and post-condition. if (casDoctor.isRepairsActive()) { try { - casDoctor.repair(aProject, aCas); + casDoctor.repair(aDocument, aDataOwner, aCas); } catch (Exception e) { - throw new DataRetrievalFailureException("Error repairing CAS of user [" - + aUsername + "] for document [" + aDocumentName + "] (" + aDocumentId - + ") in project[" + aProject.getName() + "] (" + aProject.getId() + ")", + throw new DataRetrievalFailureException( + "Error repairing CAS of user [" + aDataOwner + "] for document " + + aDocument + " in project " + aDocument.getProject(), e); } } // If the repairs are not active, then we run the analysis explicitly else { - analyze(aProject, aDocumentName, aDocumentId, aUsername, aCas); + analyze(aDocument, aDataOwner, aCas); } } } @@ -737,59 +713,55 @@ private void analyzeAndRepair(Project aProject, String aDocumentName, long aDocu * Note: {@link CasDoctor} is an optional service. If no {@link CasDoctor} implementation * is available, this method returns without doing anything. * - * @param aProject - * the project - * @param aDocumentName - * the document name (used for logging) - * @param aDocumentId - * the aDocument ID (used for logging) - * @param aUsername + * @param aDocument + * the document + * @param aDataOwner * the user owning the CAS (used for logging) * @param aCas * the CAS object */ - private void analyze(Project aProject, String aDocumentName, long aDocumentId, String aUsername, - CAS aCas) + private void analyze(SourceDocument aDocument, String aDataOwner, CAS aCas) { if (casDoctor == null) { return; } + var project = aDocument.getProject(); + try { - casDoctor.analyze(aProject, aCas); + casDoctor.analyze(aDocument, aDataOwner, aCas); } catch (CasDoctorException e) { var detailMsg = new StringBuilder(); - detailMsg.append("CAS Doctor found problems for user [").append(aUsername) - .append("] in document [").append(aDocumentName).append("] (") - .append(aDocumentId).append(") in project [").append(aProject.getName()) - .append("] (").append(aProject.getId()).append(")\n"); + detailMsg.append("CAS Doctor found problems for user [").append(aDataOwner) + .append("] in document ").append(aDocument).append(" in project ") + .append(project).append("\n"); e.getDetails().forEach( m -> detailMsg.append(String.format("- [%s] %s%n", m.level, m.message))); throw new DataRetrievalFailureException(detailMsg.toString()); } catch (Exception e) { - throw new DataRetrievalFailureException("Error analyzing CAS of user [" + aUsername - + "] in document [" + aDocumentName + "] (" + aDocumentId + ") in project[" - + aProject.getName() + "] (" + aProject.getId() + ")", e); + throw new DataRetrievalFailureException("Error analyzing CAS of user [" + aDataOwner + + "] in document " + aDocument + " in project " + project, e); } } @Override - public void exportCas(SourceDocument aDocument, String aUser, OutputStream aStream) + public void exportCas(SourceDocument aDocument, String aDataOwner, OutputStream aStream) throws IOException { // Ensure that the CAS is not being re-written and temporarily unavailable while we export // it, then add this info to a mini-session to ensure that write-access is known try (var session = CasStorageSession.openNested(true)) { - try (var access = new WithExclusiveAccess(aDocument, aUser)) { - session.add(aDocument.getId(), aUser, EXCLUSIVE_WRITE_ACCESS, access.getHolder()); + try (var access = new WithExclusiveAccess(aDocument, aDataOwner)) { + session.add(aDocument.getId(), aDataOwner, EXCLUSIVE_WRITE_ACCESS, + access.getHolder()); - driver.exportCas(aDocument, aUser, aStream); + driver.exportCas(aDocument, aDataOwner, aStream); } finally { - session.remove(aDocument.getId(), aUser); + session.remove(aDocument.getId(), aDataOwner); } } catch (IOException e) { @@ -801,19 +773,20 @@ public void exportCas(SourceDocument aDocument, String aUser, OutputStream aStre } @Override - public void importCas(SourceDocument aDocument, String aUser, InputStream aStream) + public void importCas(SourceDocument aDocument, String aDataOwner, InputStream aStream) throws IOException { // Ensure that the CAS is not being re-written and temporarily unavailable while we export // it, then add this info to a mini-session to ensure that write-access is known try (var session = CasStorageSession.openNested(true)) { - try (var access = new WithExclusiveAccess(aDocument, aUser)) { - session.add(aDocument.getId(), aUser, EXCLUSIVE_WRITE_ACCESS, access.getHolder()); + try (var access = new WithExclusiveAccess(aDocument, aDataOwner)) { + session.add(aDocument.getId(), aDataOwner, EXCLUSIVE_WRITE_ACCESS, + access.getHolder()); - driver.importCas(aDocument, aUser, aStream); + driver.importCas(aDocument, aDataOwner, aStream); } finally { - session.remove(aDocument.getId(), aUser); + session.remove(aDocument.getId(), aDataOwner); } } catch (IOException e) { @@ -825,39 +798,40 @@ public void importCas(SourceDocument aDocument, String aUser, InputStream aStrea } @Override - public void upgradeCas(SourceDocument aDocument, String aUser) throws IOException + public void upgradeCas(SourceDocument aDocument, String aDataOwner) throws IOException { Validate.notNull(aDocument, "Source document must be specified"); - Validate.notBlank(aUser, "User must be specified"); + Validate.notBlank(aDataOwner, "Data owner must be specified"); - forceActionOnCas(aDocument, aUser, // + forceActionOnCas(aDocument, aDataOwner, // (doc, user) -> driver.readCas(doc, user), - (cas) -> schemaService.upgradeCas(cas, aDocument, aUser), // + (doc, user, cas) -> schemaService.upgradeCas(cas, doc, user), // true); } @Override - public void forceActionOnCas(SourceDocument aDocument, String aUser, + public void forceActionOnCas(SourceDocument aDocument, String aDataOwner, CasStorageServiceLoader aLoader, CasStorageServiceAction aAction, boolean aSave) throws IOException { // Ensure that the CAS is not being re-written and temporarily unavailable while we check // upgrade it, then add this info to a mini-session to ensure that write-access is known try (var session = CasStorageSession.openNested(true)) { - try (var access = new WithExclusiveAccess(aDocument, aUser)) { - session.add(aDocument.getId(), aUser, EXCLUSIVE_WRITE_ACCESS, access.getHolder()); + try (var access = new WithExclusiveAccess(aDocument, aDataOwner)) { + session.add(aDocument.getId(), aDataOwner, EXCLUSIVE_WRITE_ACCESS, + access.getHolder()); - var cas = aLoader.load(aDocument, aUser); + var cas = aLoader.load(aDocument, aDataOwner); access.setCas(cas); - aAction.apply(cas); + aAction.apply(aDocument, aDataOwner, cas); if (aSave) { - realWriteCas(aDocument, aUser, cas); + realWriteCas(aDocument, aDataOwner, cas); } } finally { - session.remove(aDocument.getId(), aUser); + session.remove(aDocument.getId(), aDataOwner); } } catch (IOException e) { @@ -1118,7 +1092,7 @@ public void beforeLayerConfigurationChanged(LayerConfigurationChangedEvent aEven private void realWriteCas(SourceDocument aDocument, String aUserName, CAS aCas) throws IOException { - analyze(aDocument.getProject(), aDocument.getName(), aDocument.getId(), aUserName, aCas); + analyze(aDocument, aUserName, aCas); if (CasStorageSession.exists()) { var session = CasStorageSession.get(); diff --git a/inception/inception-curation/pom.xml b/inception/inception-curation/pom.xml index 279f61d3951..297062c480a 100644 --- a/inception/inception-curation/pom.xml +++ b/inception/inception-curation/pom.xml @@ -53,6 +53,10 @@ de.tudarmstadt.ukp.inception.app inception-schema-api + + de.tudarmstadt.ukp.inception.app + inception-io-xml + de.tudarmstadt.ukp.inception.app inception-model diff --git a/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java b/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java index 6b7132f51bd..4862f810d6c 100644 --- a/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java +++ b/inception/inception-curation/src/main/java/de/tudarmstadt/ukp/inception/curation/merge/CasMerge.java @@ -41,10 +41,6 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.FeatureStructure; import org.apache.uima.cas.text.AnnotationFS; -import org.apache.uima.util.CasCopier; -import org.dkpro.core.api.xml.type.XmlAttribute; -import org.dkpro.core.api.xml.type.XmlDocument; -import org.dkpro.core.api.xml.type.XmlNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; @@ -66,6 +62,7 @@ import de.tudarmstadt.ukp.inception.annotation.storage.CasMetadataUtils; import de.tudarmstadt.ukp.inception.curation.merge.strategy.DefaultMergeStrategy; import de.tudarmstadt.ukp.inception.curation.merge.strategy.MergeStrategy; +import de.tudarmstadt.ukp.inception.io.xml.dkprocore.XmlNodeUtils; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.api.adapter.IllegalFeatureValueException; @@ -416,21 +413,7 @@ private void clearAnnotations(SourceDocument aDocument, CAS aCas) throws UIMAExc aCas.setDocumentText(backup.getDocumentText()); transferSegmentation(aDocument.getProject(), aCas, backup); - transferDocumentStructure(aDocument.getProject(), aCas, backup); - } - - private void transferDocumentStructure(Project aProject, CAS aTarget, CAS aSource) - { - var casCopier = new CasCopier(aSource, aTarget); - // Recursively copy the structure - this does not add the copied annotations to the index - for (var doc : aSource.select(XmlDocument.class)) { - casCopier.copyFs(doc); - } - - // Add the document structure annotations to the index - aTarget.select(XmlDocument.class).forEach(aTarget::addFsToIndexes); - aTarget.select(XmlNode.class).forEach(aTarget::addFsToIndexes); - aTarget.select(XmlAttribute.class).forEach(aTarget::addFsToIndexes); + XmlNodeUtils.transferXmlDocumentStructure(aCas, backup); } /** diff --git a/inception/inception-diag/pom.xml b/inception/inception-diag/pom.xml index 146c07e774a..0095d5b575a 100644 --- a/inception/inception-diag/pom.xml +++ b/inception/inception-diag/pom.xml @@ -56,6 +56,10 @@ de.tudarmstadt.ukp.inception.app inception-annotation-storage-api + + de.tudarmstadt.ukp.inception.app + inception-documents-api + de.tudarmstadt.ukp.inception.app inception-model @@ -64,6 +68,10 @@ de.tudarmstadt.ukp.inception.app inception-support + + de.tudarmstadt.ukp.inception.app + inception-io-xml + de.tudarmstadt.ukp.inception.app inception-api-annotation diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/CasDoctor.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/CasDoctor.java index 052fe103d66..0f9cafd6a8c 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/CasDoctor.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/CasDoctor.java @@ -34,10 +34,8 @@ import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.event.EventListener; -import de.tudarmstadt.ukp.clarin.webanno.diag.checks.Check; import de.tudarmstadt.ukp.clarin.webanno.diag.config.CasDoctorProperties; -import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.SettingsUtil; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -101,10 +99,10 @@ public boolean isFatalChecks() return fatalChecks; } - public void repair(Project aProject, CAS aCas) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas) { - List messages = new ArrayList<>(); - repair(aProject, aCas, messages); + var messages = new ArrayList(); + repair(aDocument, aDataOwner, aCas, messages); if (LOG.isWarnEnabled() && !messages.isEmpty()) { messages.forEach(s -> LOG.warn("{}", s)); } @@ -115,17 +113,18 @@ public boolean isRepairsActive() return !activeRepairs.isEmpty(); } - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { // APPLY REPAIRS - long tStart = currentTimeMillis(); + var tStart = currentTimeMillis(); for (String repairId : activeRepairs) { try { - Repair repair = repairsRegistry.getExtension(repairId).orElseThrow( + var repair = repairsRegistry.getExtension(repairId).orElseThrow( () -> new NoSuchElementException("Unknown repair [" + repairId + "]")); - long tStartTask = currentTimeMillis(); + var tStartTask = currentTimeMillis(); LOG.info("CasDoctor repair [" + repair.getId() + "] running..."); - repair.repair(aProject, aCas, aMessages); + repair.repair(aDocument, aDataOwner, aCas, aMessages); LOG.info("CasDoctor repair [" + repair.getId() + "] completed in " + (currentTimeMillis() - tStartTask) + "ms"); } @@ -140,44 +139,46 @@ public void repair(Project aProject, CAS aCas, List aMessages) // POST-CONDITION: CAS must be consistent // Ensure that the repairs actually fixed the CAS - analyze(aProject, aCas, aMessages, true); + analyze(aDocument, aDataOwner, aCas, aMessages, true); } - public boolean analyze(Project aProject, CAS aCas) throws CasDoctorException + public boolean analyze(SourceDocument aDocument, String aDataOwner, CAS aCas) + throws CasDoctorException { - List messages = new ArrayList<>(); - boolean result = analyze(aProject, aCas, messages); + var messages = new ArrayList(); + var result = analyze(aDocument, aDataOwner, aCas, messages); if (LOG.isDebugEnabled()) { messages.forEach(s -> LOG.debug("{}", s)); } return result; } - public boolean analyze(Project aProject, CAS aCas, List aMessages) + public boolean analyze(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) throws CasDoctorException { - return analyze(aProject, aCas, aMessages, isFatalChecks()); + return analyze(aDocument, aDataOwner, aCas, aMessages, isFatalChecks()); } - public boolean analyze(Project aProject, CAS aCas, List aMessages, - boolean aFatalChecks) + public boolean analyze(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages, boolean aFatalChecks) throws CasDoctorException { if (activeChecks.isEmpty()) { return true; } - long tStart = currentTimeMillis(); + var tStart = currentTimeMillis(); - boolean ok = true; - for (String checkId : activeChecks) { + var ok = true; + for (var checkId : activeChecks) { try { - Check check = checksRegistry.getExtension(checkId).orElseThrow( + var check = checksRegistry.getExtension(checkId).orElseThrow( () -> new NoSuchElementException("Unknown check [" + checkId + "]")); - long tStartTask = currentTimeMillis(); + var tStartTask = currentTimeMillis(); LOG.debug("CasDoctor analysis [" + check.getId() + "] running..."); - ok &= check.check(aProject, aCas, aMessages); + ok &= check.check(aDocument, aDataOwner, aCas, aMessages); LOG.debug("CasDoctor analysis [" + check.getId() + "] completed in " + (currentTimeMillis() - tStartTask) + "ms"); } @@ -194,7 +195,7 @@ public boolean analyze(Project aProject, CAS aCas, List aMessages, throw new CasDoctorException(aMessages); } - long duration = currentTimeMillis() - tStart; + var duration = currentTimeMillis() - tStart; LOG.debug("CasDoctor completed {} checks in {}ms", activeChecks.size(), duration); serverTiming("CasDoctor", "CasDoctor (analyze)", duration); @@ -215,7 +216,7 @@ public void setActiveRepairs(String... aActiveRepairs) public void onApplicationStartedEvent(ApplicationStartedEvent aEvent) { // When under development, automatically enable all checks. - String version = SettingsUtil.getVersionProperties().getProperty(SettingsUtil.PROP_VERSION); + var version = SettingsUtil.getVersionProperties().getProperty(SettingsUtil.PROP_VERSION); if ("unknown".equals(version) || version.contains("-SNAPSHOT") || version.contains("-beta-")) { if (disableAutoScan) { @@ -228,11 +229,11 @@ public void onApplicationStartedEvent(ApplicationStartedEvent aEvent) } } - for (String checkId : activeChecks) { + for (var checkId : activeChecks) { LOG.info("Check activated: " + checkId); } - for (String repairId : activeRepairs) { + for (var repairId : activeRepairs) { LOG.info("Repair activated: " + repairId); } } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheck.java index c6ca92380f3..ac3180f8ed0 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheck.java @@ -30,7 +30,7 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.Type; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; import de.tudarmstadt.ukp.inception.support.text.TrimUtils; @@ -46,13 +46,14 @@ public AllAnnotationsStartAndEndWithCharactersCheck(AnnotationSchemaService aAnn } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { if (annotationService == null) { return true; } - var allAnnoLayers = annotationService.listAnnotationLayer(aProject); + var allAnnoLayers = annotationService.listAnnotationLayer(aDocument.getProject()); if (isEmpty(allAnnoLayers)) { return true; } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheck.java index 211786c0263..34d4298ee32 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheck.java @@ -26,11 +26,9 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.Type; -import org.apache.uima.cas.text.AnnotationFS; import org.springframework.util.CollectionUtils; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -46,20 +44,21 @@ public AllAnnotationsStartAndEndWithinSentencesCheck(AnnotationSchemaService aAn } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { if (annotationService == null) { return true; } - List allAnnoLayers = annotationService.listAnnotationLayer(aProject); + var allAnnoLayers = annotationService.listAnnotationLayer(aDocument.getProject()); allAnnoLayers.removeIf(layer -> Sentence._TypeName.equals(layer.getName())); if (CollectionUtils.isEmpty(allAnnoLayers)) { return true; } boolean ok = true; - for (AnnotationLayer layer : allAnnoLayers) { + for (var layer : allAnnoLayers) { Type type; try { type = getType(aCas, layer.getName()); @@ -75,7 +74,7 @@ public boolean check(Project aProject, CAS aCas, List aMessages) continue; } - for (AnnotationFS ann : select(aCas, type)) { + for (var ann : select(aCas, type)) { var startsOutside = aCas.select(Sentence._TypeName) .covering(ann.getBegin(), ann.getBegin()).isEmpty(); var endsOutside = aCas.select(Sentence._TypeName) diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllFeatureStructuresIndexedCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllFeatureStructuresIndexedCheck.java index ea0822da05b..a63c3a10de6 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllFeatureStructuresIndexedCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllFeatureStructuresIndexedCheck.java @@ -26,14 +26,15 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.FeatureStructure; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; public class AllFeatureStructuresIndexedCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { Map nonIndexed = getNonIndexedFSesWithOwner(aCas); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/CASMetadataTypeIsPresentCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/CASMetadataTypeIsPresentCheck.java index 91b28953e8e..51f4473dfb9 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/CASMetadataTypeIsPresentCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/CASMetadataTypeIsPresentCheck.java @@ -22,7 +22,7 @@ import org.apache.uima.cas.CAS; import de.tudarmstadt.ukp.clarin.webanno.api.type.CASMetadata; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; /** @@ -33,7 +33,8 @@ public class CASMetadataTypeIsPresentCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { if (aCas.getTypeSystem().getType(CASMetadata._TypeName) == null) { aMessages.add(LogMessage.info(this, "CAS needs upgrade to support CASMetadata which is " diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/Check.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/Check.java index d6ca956ca67..e25f582230c 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/Check.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/Check.java @@ -21,14 +21,15 @@ import org.apache.uima.cas.CAS; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.extensionpoint.Extension; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; public interface Check extends Extension { - boolean check(Project aProject, CAS aCas, List aMessages); + boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages); @Override default String getId() diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DanglingRelationsCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DanglingRelationsCheck.java index 163f76959ea..eed28e1ece2 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DanglingRelationsCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DanglingRelationsCheck.java @@ -25,11 +25,9 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.Feature; -import org.apache.uima.cas.FeatureStructure; -import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationAdapter; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -50,23 +48,24 @@ public DanglingRelationsCheck(AnnotationSchemaService aAnnotationService) } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { boolean ok = true; - for (AnnotationFS fs : aCas.getAnnotationIndex()) { - Type t = fs.getType(); + for (var fs : aCas.getAnnotationIndex()) { + var t = fs.getType(); - Feature sourceFeat = t.getFeatureByBaseName(FEAT_REL_SOURCE); - Feature targetFeat = t.getFeatureByBaseName(FEAT_REL_TARGET); + var sourceFeat = t.getFeatureByBaseName(FEAT_REL_SOURCE); + var targetFeat = t.getFeatureByBaseName(FEAT_REL_TARGET); // Is this a relation? if (!(sourceFeat != null && targetFeat != null)) { continue; } - RelationAdapter relationAdapter = (RelationAdapter) annotationService - .findAdapter(aProject, fs); + var relationAdapter = (RelationAdapter) annotationService + .findAdapter(aDocument.getProject(), fs); Feature relationSourceAttachFeature = null; Feature relationTargetAttachFeature = null; @@ -77,8 +76,8 @@ public boolean check(Project aProject, CAS aCas, List aMessages) .getFeatureByBaseName(relationAdapter.getAttachFeatureName()); } - FeatureStructure source = fs.getFeatureValue(sourceFeat); - FeatureStructure target = fs.getFeatureValue(targetFeat); + var source = fs.getFeatureValue(sourceFeat); + var target = fs.getFeatureValue(targetFeat); // Here we get the annotations that the relation is pointing to in the UI if (source != null && relationSourceAttachFeature != null) { @@ -91,7 +90,7 @@ public boolean check(Project aProject, CAS aCas, List aMessages) // Does it have null endpoints? if (source == null || target == null) { - StringBuilder message = new StringBuilder(); + var message = new StringBuilder(); message.append("Relation [" + relationAdapter.getLayer().getName() + "] with id [" + ICasUtil.getAddr(fs) + "] has loose ends."); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DocumentTextStartsWithBomCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DocumentTextStartsWithBomCheck.java index a01b346f854..88a59bba897 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DocumentTextStartsWithBomCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/DocumentTextStartsWithBomCheck.java @@ -21,14 +21,15 @@ import org.apache.uima.cas.CAS; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; public class DocumentTextStartsWithBomCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { // BOM for UTF-16BE: FE FF // BOM for UTF-16LE: FF FE diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/FeatureAttachedSpanAnnotationsTrulyAttachedCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/FeatureAttachedSpanAnnotationsTrulyAttachedCheck.java index 2f7aff12fe3..0a74438230b 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/FeatureAttachedSpanAnnotationsTrulyAttachedCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/FeatureAttachedSpanAnnotationsTrulyAttachedCheck.java @@ -28,7 +28,7 @@ import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; @@ -48,11 +48,12 @@ public FeatureAttachedSpanAnnotationsTrulyAttachedCheck( } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { - boolean ok = true; - int count = 0; - for (var layer : annotationService.listAnnotationLayer(aProject)) { + var ok = true; + var count = 0; + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!(SpanLayerSupport.TYPE.equals(layer.getType()) && layer.getAttachFeature() != null)) { continue; diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/LinksReachableThroughChainsCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/LinksReachableThroughChainsCheck.java index 742e78cc274..3483236188c 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/LinksReachableThroughChainsCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/LinksReachableThroughChainsCheck.java @@ -24,13 +24,11 @@ import java.util.List; import org.apache.uima.cas.CAS; -import org.apache.uima.cas.FeatureStructure; import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; import org.apache.uima.fit.util.FSUtil; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.WebAnnoConst; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; @@ -47,10 +45,11 @@ public LinksReachableThroughChainsCheck(AnnotationSchemaService aAnnotationServi } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { boolean ok = true; - for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!WebAnnoConst.CHAIN_TYPE.equals(layer.getType())) { continue; } @@ -72,8 +71,8 @@ public boolean check(Project aProject, CAS aCas, List aMessages) var chains = aCas.select(chainType).asList(); var links = new ArrayList<>(select(aCas, linkType)); - for (FeatureStructure chain : chains) { - AnnotationFS link = FSUtil.getFeature(chain, "first", AnnotationFS.class); + for (var chain : chains) { + var link = FSUtil.getFeature(chain, "first", AnnotationFS.class); while (link != null) { links.remove(link); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheck.java index 0974c11dd00..5506e93acbd 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheck.java @@ -24,14 +24,15 @@ import org.apache.uima.cas.CAS; import org.apache.uima.jcas.tcas.Annotation; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; public class NegativeSizeAnnotationsCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { boolean ok = true; diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheck.java index 0ebe7fc9c95..bcb00af9780 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheck.java @@ -34,8 +34,7 @@ import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.dependency.Dependency; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -52,19 +51,20 @@ public NoMultipleIncomingRelationsCheck(AnnotationSchemaService aAnnotationServi } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { if (annotationService == null) { return true; } - List allAnnoLayers = annotationService.listAnnotationLayer(aProject); + var allAnnoLayers = annotationService.listAnnotationLayer(aDocument.getProject()); if (CollectionUtils.isEmpty(allAnnoLayers)) { return true; } boolean ok = true; - for (AnnotationLayer layer : allAnnoLayers) { + for (var layer : allAnnoLayers) { if (!RELATION_TYPE.equals(layer.getType())) { continue; @@ -89,14 +89,13 @@ public boolean check(Project aProject, CAS aCas, List aMessages) // to provide a better debugging output. Map incoming = new HashMap<>(); - for (AnnotationFS rel : select(aCas, type)) { + for (var rel : select(aCas, type)) { - AnnotationFS source = getFeature(rel, FEAT_REL_SOURCE, AnnotationFS.class); - AnnotationFS target = getFeature(rel, FEAT_REL_TARGET, AnnotationFS.class); + var source = getFeature(rel, FEAT_REL_SOURCE, AnnotationFS.class); + var target = getFeature(rel, FEAT_REL_TARGET, AnnotationFS.class); - AnnotationFS existingSource = incoming.get(target); + var existingSource = incoming.get(target); if (existingSource != null) { - // Debug output should include sentence number to make the orientation // easier Optional sentenceNumber = Optional.empty(); @@ -118,7 +117,6 @@ public boolean check(Project aProject, CAS aCas, List aMessages) target.getCoveredText())); } else { - aMessages.add(LogMessage.warn(this, "Relation [%s] -> [%s] points to span that already has an " + "incoming relation [%s] -> [%s].", diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoZeroSizeTokensAndSentencesCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoZeroSizeTokensAndSentencesCheck.java index 28cc1d80ed3..104054ccc02 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoZeroSizeTokensAndSentencesCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoZeroSizeTokensAndSentencesCheck.java @@ -25,7 +25,7 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.text.AnnotationFS; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -33,7 +33,8 @@ public class NoZeroSizeTokensAndSentencesCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { boolean ok = true; diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/RelationOffsetsCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/RelationOffsetsCheck.java index b0cef8c9b29..d94c2e47dd5 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/RelationOffsetsCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/RelationOffsetsCheck.java @@ -28,8 +28,7 @@ import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.WebAnnoConst; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; @@ -51,11 +50,12 @@ public RelationOffsetsCheck(AnnotationSchemaService aAnnotationService) } @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { boolean ok = true; - for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!RELATION_TYPE.equals(layer.getType())) { continue; } @@ -70,9 +70,8 @@ public boolean check(Project aProject, CAS aCas, List aMessages) continue; } - for (AnnotationFS rel : select(aCas, type)) { - AnnotationFS target = getFeature(rel, WebAnnoConst.FEAT_REL_TARGET, - AnnotationFS.class); + for (var rel : select(aCas, type)) { + var target = getFeature(rel, WebAnnoConst.FEAT_REL_TARGET, AnnotationFS.class); if ((rel.getBegin() != target.getBegin()) || (rel.getEnd() != target.getEnd())) { aMessages.add(new LogMessage(this, LogLevel.ERROR, "Relation offsets [%d,%d] to not match target offsets [%d,%d]", diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheck.java index 0134f4c8877..86082fbbe4b 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheck.java @@ -25,7 +25,7 @@ import org.apache.uima.cas.CAS; import org.apache.uima.jcas.tcas.Annotation; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -34,7 +34,8 @@ public class TokensAndSententencedDoNotOverlapCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { return checkTokens(aCas, aMessages) && checkSentences(aCas, aMessages); } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UniqueDocumentAnnotationCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UniqueDocumentAnnotationCheck.java index df6bbcd118a..be98577b75e 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UniqueDocumentAnnotationCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UniqueDocumentAnnotationCheck.java @@ -22,7 +22,7 @@ import org.apache.uima.cas.CAS; import org.apache.uima.jcas.tcas.DocumentAnnotation; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; /** @@ -32,7 +32,8 @@ public class UniqueDocumentAnnotationCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { if (aCas.select(DocumentAnnotation.class).count() > 1) { aMessages.add(LogMessage.error(this, "There is more than one document annotation!")); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UnreachableAnnotationsCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UnreachableAnnotationsCheck.java index 4ed9b0785d7..e8e599b4fb2 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UnreachableAnnotationsCheck.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/UnreachableAnnotationsCheck.java @@ -34,7 +34,7 @@ import org.apache.uima.cas.impl.CASImpl; import org.apache.uima.resource.ResourceInitializationException; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; import de.tudarmstadt.ukp.inception.support.uima.WebAnnoCasUtil; @@ -42,7 +42,8 @@ public class UnreachableAnnotationsCheck implements Check { @Override - public boolean check(Project aProject, CAS aCas, List aMessages) + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { var casImpl = (CASImpl) getRealCas(aCas); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/XmlStructurePresentInCurationCasCheck.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/XmlStructurePresentInCurationCasCheck.java new file mode 100644 index 00000000000..0e6663327ab --- /dev/null +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/XmlStructurePresentInCurationCasCheck.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * 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 de.tudarmstadt.ukp.clarin.webanno.diag.checks; + +import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.CURATION_USER; +import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCauseMessage; + +import java.io.IOException; +import java.util.List; + +import org.apache.uima.cas.CAS; +import org.dkpro.core.api.xml.type.XmlDocument; + +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; +import de.tudarmstadt.ukp.inception.documents.api.DocumentService; +import de.tudarmstadt.ukp.inception.support.logging.LogMessage; + +public class XmlStructurePresentInCurationCasCheck + implements Check +{ + private final DocumentService documentService; + + public XmlStructurePresentInCurationCasCheck(DocumentService aDocumentService) + { + documentService = aDocumentService; + } + + @Override + public boolean check(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) + { + if (!CURATION_USER.equals(aDataOwner)) { + // We want to check only the curation CAS + return true; + } + + if (!aCas.select(XmlDocument.class).isEmpty()) { + // Document structure already exists + return true; + } + + try { + var initialCas = documentService.createOrReadInitialCas(aDocument); + + if (initialCas.select(XmlDocument.class).isEmpty()) { + // Initial CAS also does not contain a document structure, so we are good + return true; + } + + // If we get here, the curation CAS does not contain a document structure + // but the initial CAS did, so the structure is missing from the curation CAS. + aMessages.add(LogMessage.error(this, + "XML document structure that is present in the initial CAS has not been " + + "copied over to the curation CAS")); + return false; + } + catch (IOException e) { + aMessages.add(LogMessage.error(this, "Unable to obtain initial CAS: %s", + getRootCauseMessage(e))); + return false; + } + } +} diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/config/CasDoctorAutoConfiguration.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/config/CasDoctorAutoConfiguration.java index 3b4a4aab827..eae0e1f07ea 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/config/CasDoctorAutoConfiguration.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/config/CasDoctorAutoConfiguration.java @@ -46,6 +46,7 @@ import de.tudarmstadt.ukp.clarin.webanno.diag.checks.TokensAndSententencedDoNotOverlapCheck; import de.tudarmstadt.ukp.clarin.webanno.diag.checks.UniqueDocumentAnnotationCheck; import de.tudarmstadt.ukp.clarin.webanno.diag.checks.UnreachableAnnotationsCheck; +import de.tudarmstadt.ukp.clarin.webanno.diag.checks.XmlStructurePresentInCurationCasCheck; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.CoverAllTextInSentencesRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.ReattachFeatureAttachedSpanAnnotationsRepair; @@ -57,9 +58,11 @@ import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.RemoveDanglingRelationsRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.RemoveZeroSizeTokensAndSentencesRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair; +import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.ReplaceXmlStructureInCurationCasRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.SwitchBeginAndEndOnNegativeSizedAnnotationsRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.TrimAnnotationsRepair; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.UpgradeCasRepair; +import de.tudarmstadt.ukp.inception.documents.api.DocumentService; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; @Configuration @@ -265,4 +268,18 @@ public RemoveBomRepair removeBomRepair() { return new RemoveBomRepair(); } + + @Bean + public XmlStructurePresentInCurationCasCheck xmlStructurePresentInCurationCasCheck( + DocumentService aDocumentService) + { + return new XmlStructurePresentInCurationCasCheck(aDocumentService); + } + + @Bean + public ReplaceXmlStructureInCurationCasRepair replaceXmlStructureInCurationCasRepair( + DocumentService aDocumentService) + { + return new ReplaceXmlStructureInCurationCasRepair(aDocumentService); + } } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepair.java index 52dd95269e7..3e50859593e 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepair.java @@ -25,7 +25,7 @@ import org.apache.uima.cas.Type; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -34,7 +34,8 @@ public class CoverAllTextInSentencesRepair implements Repair { @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { int prevSentenceEnd = 0; for (Sentence sentence : aCas.select(Sentence.class)) { diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair.java index 649839b68bf..d950e01c250 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair.java @@ -27,12 +27,10 @@ import java.util.List; import org.apache.uima.cas.CAS; -import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -50,35 +48,36 @@ public ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair( } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { - for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!(SpanLayerSupport.TYPE.equals(layer.getType()) && layer.getAttachFeature() != null)) { continue; } - Type attachType = getType(aCas, layer.getAttachType().getName()); - String attachFeature = layer.getAttachFeature().getName(); + var attachType = getType(aCas, layer.getAttachType().getName()); + var attachFeature = layer.getAttachFeature().getName(); - int count = 0; + var count = 0; // Go over the layer that has an attach feature (e.g. Token) and make sure that it is // filled // anno -> e.g. Lemma // attach -> e.g. Token - for (AnnotationFS anno : select(aCas, getType(aCas, layer.getName()))) { + for (var anno : select(aCas, getType(aCas, layer.getName()))) { // Here we fetch all annotations of the layer we attach to at the relevant position, // e.g. Token - List attachables = selectCovered(attachType, anno); + var attachables = selectCovered(attachType, anno); if (attachables.size() > 1) { aMessages.add(LogMessage.error(this, "There is more than one attachable annotation for [%s] on layer [%s].", layer.getName(), attachType.getName())); } - for (AnnotationFS attach : attachables) { - AnnotationFS existing = getFeature(attach, attachFeature, AnnotationFS.class); + for (var attach : attachables) { + var existing = getFeature(attach, attachFeature, AnnotationFS.class); // So there is an annotation to which we could attach and it does not yet have // an annotation attached, so we attach to it. @@ -102,17 +101,15 @@ public void repair(Project aProject, CAS aCas, List aMessages) // // attach -> e.g. Token // candidates -> e.g. Lemma - List toDelete = new ArrayList<>(); - for (AnnotationFS attach : select(aCas, attachType)) { - List candidates = selectCovered(getType(aCas, layer.getName()), - attach); + var toDelete = new ArrayList(); + for (var attach : select(aCas, attachType)) { + var candidates = selectCovered(getType(aCas, layer.getName()), attach); if (!candidates.isEmpty()) { // One of the candidates should already be attached - AnnotationFS attachedCandidate = getFeature(attach, attachFeature, - AnnotationFS.class); + var attachedCandidate = getFeature(attach, attachFeature, AnnotationFS.class); - for (AnnotationFS candidate : candidates) { + for (var candidate : candidates) { if (!candidate.equals(attachedCandidate)) { toDelete.add(candidate); } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsRepair.java index 36a3177a0bb..af594ae9235 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReattachFeatureAttachedSpanAnnotationsRepair.java @@ -26,12 +26,10 @@ import java.util.List; import org.apache.uima.cas.CAS; -import org.apache.uima.cas.Type; import org.apache.uima.cas.text.AnnotationFS; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -48,30 +46,31 @@ public ReattachFeatureAttachedSpanAnnotationsRepair(AnnotationSchemaService aAnn } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { - for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!(SpanLayerSupport.TYPE.equals(layer.getType()) && layer.getAttachFeature() != null)) { continue; } - Type attachType = getType(aCas, layer.getAttachType().getName()); - String attachFeature = layer.getAttachFeature().getName(); + var attachType = getType(aCas, layer.getAttachType().getName()); + var attachFeature = layer.getAttachFeature().getName(); - int count = 0; - int nonNullCount = 0; + var count = 0; + var nonNullCount = 0; // Go over the layer that has an attach feature (e.g. Token) and make sure that it is // filled // anno -> e.g. Lemma // attach -> e.g. Token // Here we iterate over the attached layer, e.g. Lemma - for (AnnotationFS anno : select(aCas, getType(aCas, layer.getName()))) { + for (var anno : select(aCas, getType(aCas, layer.getName()))) { // Here we fetch all annotations of the layer we attach to at the relevant position, // e.g. Token - for (AnnotationFS attach : selectCovered(attachType, anno)) { - AnnotationFS existing = getFeature(attach, attachFeature, AnnotationFS.class); + for (var attach : selectCovered(attachType, anno)) { + var existing = getFeature(attach, attachFeature, AnnotationFS.class); if (existing == null) { setFeature(attach, layer.getAttachFeature().getName(), anno); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReindexFeatureAttachedSpanAnnotationsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReindexFeatureAttachedSpanAnnotationsRepair.java index 000869bc800..82adf868c52 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReindexFeatureAttachedSpanAnnotationsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReindexFeatureAttachedSpanAnnotationsRepair.java @@ -30,8 +30,7 @@ import org.apache.uima.cas.text.AnnotationFS; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; @@ -53,25 +52,25 @@ public ReindexFeatureAttachedSpanAnnotationsRepair(AnnotationSchemaService aAnno } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { Map nonIndexed = getNonIndexedFSesWithOwner(aCas); - for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!(SpanLayerSupport.TYPE.equals(layer.getType()) && layer.getAttachFeature() != null)) { continue; } - int count = 0; + var count = 0; // Go over the layer that has an attach feature (e.g. Token) and make sure that it is // filled // attach -> e.g. Token // anno -> e.g. Lemma - for (AnnotationFS attach : select(aCas, - getType(aCas, layer.getAttachType().getName()))) { - AnnotationFS anno = getFeature(attach, layer.getAttachFeature().getName(), + for (var attach : select(aCas, getType(aCas, layer.getAttachType().getName()))) { + var anno = getFeature(attach, layer.getAttachFeature().getName(), AnnotationFS.class); if (anno != null && nonIndexed.containsKey(anno)) { aCas.addFsToIndexes(anno); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RelationOffsetsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RelationOffsetsRepair.java index 57a2ac6b2c7..655eea59db9 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RelationOffsetsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RelationOffsetsRepair.java @@ -30,8 +30,7 @@ import org.apache.uima.cas.text.AnnotationFS; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.WebAnnoConst; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; @@ -54,10 +53,11 @@ public RelationOffsetsRepair(AnnotationSchemaService aAnnotationService) } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { - List fixedRels = new ArrayList<>(); - for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { + var fixedRels = new ArrayList(); + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!WebAnnoConst.RELATION_TYPE.equals(layer.getType())) { continue; } @@ -72,9 +72,8 @@ public void repair(Project aProject, CAS aCas, List aMessages) continue; } - for (AnnotationFS rel : select(aCas, type)) { - AnnotationFS target = getFeature(rel, WebAnnoConst.FEAT_REL_TARGET, - AnnotationFS.class); + for (var rel : select(aCas, type)) { + var target = getFeature(rel, WebAnnoConst.FEAT_REL_TARGET, AnnotationFS.class); if ((rel.getBegin() != target.getBegin()) || (rel.getEnd() != target.getEnd())) { fixedRels.add(rel); setFeature(rel, CAS.FEATURE_BASE_NAME_BEGIN, target.getBegin()); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepair.java index 6ef8630ebdd..db84b4518b6 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepair.java @@ -27,7 +27,7 @@ import org.apache.uima.jcas.tcas.Annotation; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @Safe(false) @@ -35,7 +35,8 @@ public class RemoveBomRepair implements Repair { @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { var cas = getRealCas(aCas); var text = cas.getDocumentText(); diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingChainLinksRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingChainLinksRepair.java index 9dc5599ca25..10c4b616ada 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingChainLinksRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingChainLinksRepair.java @@ -28,7 +28,7 @@ import org.apache.uima.jcas.tcas.Annotation; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.WebAnnoConst; import de.tudarmstadt.ukp.inception.support.logging.LogLevel; @@ -46,9 +46,10 @@ public RemoveDanglingChainLinksRepair(AnnotationSchemaService aAnnotationService } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { - for (var layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { if (!WebAnnoConst.CHAIN_TYPE.equals(layer.getType())) { continue; } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingFeatureAttachedSpanAnnotationsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingFeatureAttachedSpanAnnotationsRepair.java index 611d5cad021..3ab8aa0c5aa 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingFeatureAttachedSpanAnnotationsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingFeatureAttachedSpanAnnotationsRepair.java @@ -30,7 +30,7 @@ import org.apache.uima.cas.text.AnnotationFS; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -48,11 +48,12 @@ public RemoveDanglingFeatureAttachedSpanAnnotationsRepair( } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { var nonIndexed = getNonIndexedFSesWithOwner(aCas); - for (var layer : annotationService.listAnnotationLayer(aProject)) { + for (var layer : annotationService.listAnnotationLayer(aDocument.getProject())) { var count = 0; if (!(SpanLayerSupport.TYPE.equals(layer.getType()) diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepair.java index 2783d1cbeb6..7ce1d292074 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepair.java @@ -30,7 +30,7 @@ import org.apache.uima.cas.text.AnnotationFS; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationAdapter; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.adapter.TypeAdapter; @@ -58,7 +58,8 @@ public RemoveDanglingRelationsRepair(AnnotationSchemaService aAnnotationService) } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { var nonIndexed = getNonIndexedFSes(aCas); @@ -72,7 +73,7 @@ public void repair(Project aProject, CAS aCas, List aMessages) TypeAdapter adapter = null; try { adapter = adapterCache.computeIfAbsent(t.getName(), - $ -> annotationService.findAdapter(aProject, fs)); + $ -> annotationService.findAdapter(aDocument.getProject(), fs)); } catch (NoResultException e) { // Ignore diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveZeroSizeTokensAndSentencesRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveZeroSizeTokensAndSentencesRepair.java index a4d92709874..cdac9859516 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveZeroSizeTokensAndSentencesRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveZeroSizeTokensAndSentencesRepair.java @@ -27,7 +27,7 @@ import org.apache.uima.fit.util.FSUtil; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; import de.tudarmstadt.ukp.inception.support.uima.WebAnnoCasUtil; @@ -36,7 +36,8 @@ public class RemoveZeroSizeTokensAndSentencesRepair implements Repair { @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { for (AnnotationFS s : selectSentences(aCas)) { if (s.getBegin() >= s.getEnd()) { diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/Repair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/Repair.java index 1e635fdce46..16ac753a8b8 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/Repair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/Repair.java @@ -25,14 +25,14 @@ import org.apache.uima.cas.CAS; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.extensionpoint.Extension; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; public interface Repair extends Extension { - void repair(Project aProject, CAS aCas, List aMessages); + void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, List aMessages); @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReplaceXmlStructureInCurationCasRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReplaceXmlStructureInCurationCasRepair.java new file mode 100644 index 00000000000..9280495f090 --- /dev/null +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/ReplaceXmlStructureInCurationCasRepair.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * 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 de.tudarmstadt.ukp.clarin.webanno.diag.repairs; + +import static de.tudarmstadt.ukp.inception.io.xml.dkprocore.XmlNodeUtils.removeXmlDocumentStructure; +import static de.tudarmstadt.ukp.inception.io.xml.dkprocore.XmlNodeUtils.transferXmlDocumentStructure; +import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.CURATION_USER; +import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCauseMessage; + +import java.io.IOException; +import java.util.List; + +import org.apache.uima.cas.CAS; +import org.dkpro.core.api.xml.type.XmlDocument; + +import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; +import de.tudarmstadt.ukp.inception.documents.api.DocumentService; +import de.tudarmstadt.ukp.inception.support.logging.LogMessage; + +@Safe(false) +public class ReplaceXmlStructureInCurationCasRepair + implements Repair +{ + private final DocumentService documentService; + + public ReplaceXmlStructureInCurationCasRepair(DocumentService aDocumentService) + { + documentService = aDocumentService; + } + + @Override + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) + { + if (!CURATION_USER.equals(aDataOwner)) { + // We want to repair only the curation CAS + return; + } + + try { + var initialCas = documentService.createOrReadInitialCas(aDocument); + + if (initialCas.select(XmlDocument.class).isEmpty()) { + // Initial CAS also does not contain a document structure, so we are good + return; + } + + var deleted = removeXmlDocumentStructure(aCas); + var added = transferXmlDocumentStructure(aCas, initialCas); + + var operation = "replaced"; + if (deleted == 0) { + operation = "added"; + } + + aMessages.add(LogMessage.error(this, + "XML document structure has been %s using the structure from the initial CAS (nodes: %d removed, %d added)", + operation, deleted, added)); + } + catch (IOException e) { + aMessages.add(LogMessage.error(this, "Unable to obtain initial CAS: %s", + getRootCauseMessage(e))); + } + } +} diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepair.java index 16d29fcc338..b5305798601 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepair.java @@ -25,7 +25,7 @@ import org.apache.uima.jcas.tcas.Annotation; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @Safe(false) @@ -33,7 +33,8 @@ public class SwitchBeginAndEndOnNegativeSizedAnnotationsRepair implements Repair { @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { for (Annotation ann : aCas.select(Annotation.class)) { if (ann.getBegin() > ann.getEnd()) { diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/TrimAnnotationsRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/TrimAnnotationsRepair.java index 32fe9568c80..50997b01e7a 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/TrimAnnotationsRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/TrimAnnotationsRepair.java @@ -31,7 +31,7 @@ import org.apache.uima.cas.Type; import org.apache.uima.jcas.tcas.Annotation; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; import de.tudarmstadt.ukp.inception.support.text.TrimUtils; @@ -47,9 +47,10 @@ public TrimAnnotationsRepair(AnnotationSchemaService aAnnotationService) } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { - var allAnnoLayers = annotationService.listAnnotationLayer(aProject); + var allAnnoLayers = annotationService.listAnnotationLayer(aDocument.getProject()); if (isEmpty(allAnnoLayers)) { return; } diff --git a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/UpgradeCasRepair.java b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/UpgradeCasRepair.java index 0fb9004ec13..1e9e64d51dc 100644 --- a/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/UpgradeCasRepair.java +++ b/inception/inception-diag/src/main/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/UpgradeCasRepair.java @@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory; import de.tudarmstadt.ukp.clarin.webanno.diag.repairs.Repair.Safe; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; import de.tudarmstadt.ukp.inception.support.uima.WebAnnoCasUtil; @@ -56,7 +56,8 @@ public UpgradeCasRepair(AnnotationSchemaService aAnnotationService) } @Override - public void repair(Project aProject, CAS aCas, List aMessages) + public void repair(SourceDocument aDocument, String aDataOwner, CAS aCas, + List aMessages) { try { var casImpl = (CASImpl) getRealCas(aCas); @@ -65,7 +66,7 @@ public void repair(Project aProject, CAS aCas, List aMessages) var bytesBefore = size(serializeCASComplete(casImpl)); int bytesAfter; - annotationService.upgradeCas(aCas, aProject); + annotationService.upgradeCas(aCas, aDocument.getProject()); aMessages.add(LogMessage.info(this, "CAS upgraded.")); var annotationCountsAfter = countFeatureStructures(casImpl); diff --git a/inception/inception-diag/src/main/resources/META-INF/asciidoc/user-guide/casdoctor.adoc b/inception/inception-diag/src/main/resources/META-INF/asciidoc/user-guide/casdoctor.adoc index 7e3e40cb096..ea194b541b4 100644 --- a/inception/inception-diag/src/main/resources/META-INF/asciidoc/user-guide/casdoctor.adoc +++ b/inception/inception-diag/src/main/resources/META-INF/asciidoc/user-guide/casdoctor.adoc @@ -224,21 +224,29 @@ Removing them is harmless and reduces memory and disk space usage. [[check_AllAnnotationsStartAndEndWithCharactersCheck]] === All annotations start and end with characters [horizontal] -ID:: `check_AllAnnotationsStartAndEndWithCharactersCheck` +ID:: `AllAnnotationsStartAndEndWithCharactersCheck` Related repairs:: <> -Checks if all annotations start and end with a character (i.e. not a whitespace). Annotations that start or end with a -whitespace character can cause problems during rendering. Trimming whitespace at the begin and end is typically as -harmless procedure. +Checks if all annotations start and end with a character (i.e. not a whitespace). Annotations that start or end with a whitespace character can cause problems during rendering. +Trimming whitespace at the begin and end is typically as harmless procedure. [[check_DocumentTextStartsWithBomCheck]] === Document text starts with Byte Order Mark [horizontal] -ID:: `check_DocumentTextStartsWithBomCheck` +ID:: `DocumentTextStartsWithBomCheck` Related repairs:: <> Checks if the document text starts with a Byte Order Mark (BOM). +[[check_XmlStructurePresentInCurationCasCheck]] +=== XML structure is present in curation CAS +[horizontal] +ID:: `XmlStructurePresentInCurationCasCheck` +Related repairs:: <> + +Checks if an XML structure that may have been extracted from the source document is present in the curation CAS. +If it is not present, this check will fail. + [[sect_repairs]] == Repairs @@ -251,9 +259,8 @@ ID:: `ReattachFeatureAttachedSpanAnnotationsRepair` This repair action attempts to attach spans that should be attached to another span, but are not. E.g. it tries to set the `pos` feature of tokens to the POS annotation for that respective token. -The action is not performed if there are multiple stacked annotations to choose from. Stacked -attached annotations would be an indication of a bug because attached layers are not allowed to -stack. +The action is not performed if there are multiple stacked annotations to choose from. +Stacked attached annotations would be an indication of a bug because attached layers are not allowed to stack. This is a safe repair action as it does not delete anything. @@ -265,10 +272,10 @@ This is a safe repair action as it does not delete anything. ID:: `ReattachFeatureAttachedSpanAnnotationsAndDeleteExtrasRepair` This is a destructive variant of <>. In -addition to re-attaching unattached annotations, it also removes all extra candidates that cannot -be attached. For example, if there are two unattached Lemma annotations at the position of a Token -annotation, then one will be attached and the other will be deleted. Which one is attached and -which one is deleted is undefined. +addition to re-attaching unattached annotations, it also removes all extra candidates that cannot be attached. +For example, if there are two unattached Lemma annotations at the position of a Token +annotation, then one will be attached and the other will be deleted. +Which one is attached and which one is deleted is undefined. [[repair_ReindexFeatureAttachedSpanAnnotationsRepair]] @@ -277,8 +284,8 @@ which one is deleted is undefined. [horizontal] ID:: `ReindexFeatureAttachedSpanAnnotationsRepair` -This repair locates annotations that are reachable via a attach feature but which are not actually -indexed in the CAS. Such annotations are then added back to the CAS indexes. +This repair locates annotations that are reachable via a attach feature but which are not actually indexed in the CAS. +Such annotations are then added back to the CAS indexes. This is a safe repair action as it does not delete anything. @@ -289,9 +296,8 @@ This is a safe repair action as it does not delete anything. [horizontal] ID:: `RelationOffsetsRepair` -Fixes that the offsets of relations match the target of the relation. This mirrors the DKPro -Core convention that the offsets of a dependency relation must match the offsets of the -dependent. +Fixes that the offsets of relations match the target of the relation. +This mirrors the DKPro Core convention that the offsets of a dependency relation must match the offsets of the dependent. [[repair_RemoveDanglingChainLinksRepair]] @@ -408,3 +414,11 @@ NOTE: Run the checks again after applying this repair as certain annotations can ID:: `RemoveBomRepair` This repair removes the Byte Order Mark at the start of the document and adjusts all annotation offsets accordingly. + +[[repair_ReplaceXmlStructureInCurationCasRepair]] +=== Relace XML structure in the curation CAS + +[horizontal] +ID:: `ReplaceXmlStructureInCurationCasRepair` + +This repair ensures the XML document structure that may have been extracted from the source document is also present in the curation CAS. Any potentially existing XML document structure int he curation CAS will be removed and replaced with the structure from the source document. diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsIndexedCheckTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsIndexedCheckTest.java index d4f44b531c6..067f777bb4b 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsIndexedCheckTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsIndexedCheckTest.java @@ -79,7 +79,7 @@ public void testFail() throws Exception .toArray(String[]::new)); // A project is not required for this check - var result = cd.analyze(null, cas, messages); + var result = cd.analyze(null, null, cas, messages); messages.forEach($ -> LOG.debug("{}", $)); @@ -126,7 +126,7 @@ public void testOK() throws Exception .toArray(String[]::new)); // A project is not required for this check - var result = cd.analyze(null, cas, messages); + var result = cd.analyze(null, null, cas, messages); messages.forEach($ -> LOG.debug("{}", $)); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheckTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheckTest.java index 1bb1f383a82..e82a52cfa0c 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheckTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithCharactersCheckTest.java @@ -39,6 +39,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.ner.type.NamedEntity; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; @@ -60,13 +61,18 @@ static class Config AllAnnotationsStartAndEndWithCharactersCheck sut; Project project; + SourceDocument document; + String dataOwner; JCas jCas; List layers; @BeforeEach void setup() throws Exception { - project = new Project(); + project = Project.builder().build(); + document = SourceDocument.builder() // + .withProject(project) // + .build(); jCas = JCasFactory.createJCas(); var namedEntityLayer = new AnnotationLayer(); @@ -88,7 +94,7 @@ void test() var messages = new ArrayList(); - var result = sut.check(project, jCas.getCas(), messages); + var result = sut.check(document, dataOwner, jCas.getCas(), messages); assertThat(result).isFalse(); assertThat(messages).hasSize(1); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheckTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheckTest.java index 9446139fc17..3ffb33afb7b 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheckTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/AllAnnotationsStartAndEndWithinSentencesCheckTest.java @@ -38,6 +38,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.ner.type.NamedEntity; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; @@ -59,16 +60,21 @@ static class Config AllAnnotationsStartAndEndWithinSentencesCheck sut; Project project; + SourceDocument document; + String dataOwner; JCas jCas; List layers; @BeforeEach void setup() throws Exception { - project = new Project(); + project = Project.builder().build(); + document = SourceDocument.builder() // + .withProject(project) // + .build(); jCas = JCasFactory.createJCas(); - AnnotationLayer namedEntityLayer = new AnnotationLayer(); + var namedEntityLayer = new AnnotationLayer(); namedEntityLayer.setName(NamedEntity._TypeName); layers = asList(namedEntityLayer); } @@ -88,7 +94,7 @@ void test() var messages = new ArrayList(); - var result = sut.check(project, jCas.getCas(), messages); + var result = sut.check(document, dataOwner, jCas.getCas(), messages); assertThat(result).isFalse(); assertThat(messages).hasSize(1); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheckTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheckTest.java index 2a582df5794..d7f06c9f435 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheckTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NegativeSizeAnnotationsCheckTest.java @@ -28,20 +28,21 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; class NegativeSizeAnnotationsCheckTest { NegativeSizeAnnotationsCheck sut; - Project project; + SourceDocument document; + String dataOwner; JCas jCas; @BeforeEach void setup() throws Exception { sut = new NegativeSizeAnnotationsCheck(); - project = new Project(); + document = SourceDocument.builder().build(); jCas = JCasFactory.createJCas(); } @@ -56,7 +57,7 @@ void test() var messages = new ArrayList(); - var result = sut.check(project, jCas.getCas(), messages); + var result = sut.check(document, dataOwner, jCas.getCas(), messages); assertThat(result).isFalse(); assertThat(messages).hasSize(1); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheckTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheckTest.java index c9ed2d9ef9f..ef337efa2a4 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheckTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/NoMultipleIncomingRelationsCheckTest.java @@ -17,16 +17,15 @@ */ package de.tudarmstadt.ukp.clarin.webanno.diag.checks; +import static java.util.Arrays.asList; +import static org.apache.uima.fit.factory.JCasFactory.createJCas; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.when; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.apache.uima.fit.factory.JCasFactory; -import org.apache.uima.jcas.JCas; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -37,11 +36,14 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; +import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.coref.type.CoreferenceChain; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.dependency.Dependency; +import de.tudarmstadt.ukp.inception.annotation.layer.chain.ChainLayerSupport; +import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationLayerSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; -import de.tudarmstadt.ukp.inception.support.WebAnnoConst; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @ExtendWith(SpringExtension.class) @@ -59,42 +61,54 @@ static class Config @Autowired NoMultipleIncomingRelationsCheck sut; + Project project; + SourceDocument document; + String dataOwner; + + @BeforeEach + void setup() throws Exception + { + project = Project.builder().build(); + document = SourceDocument.builder() // + .withProject(project) // + .build(); + } + @Test public void testFail() throws Exception { - AnnotationLayer relationLayer = new AnnotationLayer(); + var relationLayer = new AnnotationLayer(); relationLayer.setName(Dependency.class.getName()); - relationLayer.setType(WebAnnoConst.RELATION_TYPE); - when(annotationService.listAnnotationLayer(Mockito.isNull())) - .thenReturn(Arrays.asList(relationLayer)); + relationLayer.setType(RelationLayerSupport.TYPE); + when(annotationService.listAnnotationLayer(project)).thenReturn(asList(relationLayer)); - JCas jcas = JCasFactory.createJCas(); + var jcas = createJCas(); jcas.setDocumentText("This is a test."); - Token spanThis = new Token(jcas, 0, 4); + var spanThis = new Token(jcas, 0, 4); spanThis.addToIndexes(); - Token spanIs = new Token(jcas, 5, 7); + var spanIs = new Token(jcas, 5, 7); spanIs.addToIndexes(); - Token spanA = new Token(jcas, 8, 9); + var spanA = new Token(jcas, 8, 9); spanA.addToIndexes(); - Dependency dep1 = new Dependency(jcas, 0, 7); + var dep1 = new Dependency(jcas, 0, 7); dep1.setGovernor(spanThis); dep1.setDependent(spanIs); dep1.addToIndexes(); - Dependency dep2 = new Dependency(jcas, 0, 9); + var dep2 = new Dependency(jcas, 0, 9); dep2.setGovernor(spanA); dep2.setDependent(spanIs); dep2.addToIndexes(); - List messages = new ArrayList<>(); + var messages = new ArrayList(); - boolean result = sut.check(null, jcas.getCas(), messages); + var result = sut.check(document, dataOwner, jcas.getCas(), messages); messages.forEach(System.out::println); @@ -111,39 +125,38 @@ public void testFail() throws Exception @Test public void testOK() throws Exception { - AnnotationLayer relationLayer = new AnnotationLayer(); + var relationLayer = new AnnotationLayer(); relationLayer.setName(Dependency.class.getName()); + relationLayer.setType(RelationLayerSupport.TYPE); + when(annotationService.listAnnotationLayer(Mockito.isNull())) + .thenReturn(asList(relationLayer)); - relationLayer.setType(WebAnnoConst.RELATION_TYPE); - Mockito.when(annotationService.listAnnotationLayer(Mockito.isNull())) - .thenReturn(Arrays.asList(relationLayer)); - - JCas jcas = JCasFactory.createJCas(); + var jcas = createJCas(); jcas.setDocumentText("This is a test."); - Token spanThis = new Token(jcas, 0, 4); + var spanThis = new Token(jcas, 0, 4); spanThis.addToIndexes(); - Token spanIs = new Token(jcas, 6, 8); + var spanIs = new Token(jcas, 6, 8); spanIs.addToIndexes(); - Token spanA = new Token(jcas, 9, 10); + var spanA = new Token(jcas, 9, 10); spanA.addToIndexes(); - Dependency dep1 = new Dependency(jcas, 0, 8); + var dep1 = new Dependency(jcas, 0, 8); dep1.setGovernor(spanThis); dep1.setDependent(spanIs); dep1.addToIndexes(); - Dependency dep2 = new Dependency(jcas, 6, 10); + var dep2 = new Dependency(jcas, 6, 10); dep2.setGovernor(spanIs); dep2.setDependent(spanA); dep2.addToIndexes(); - List messages = new ArrayList<>(); + var messages = new ArrayList(); - boolean result = sut.check(null, jcas.getCas(), messages); + var result = sut.check(document, dataOwner, jcas.getCas(), messages); messages.forEach(System.out::println); @@ -154,39 +167,38 @@ public void testOK() throws Exception public void testOkBecauseCoref() throws Exception { - AnnotationLayer relationLayer = new AnnotationLayer(); + var relationLayer = new AnnotationLayer(); relationLayer.setName(CoreferenceChain.class.getName()); + relationLayer.setType(ChainLayerSupport.TYPE); + when(annotationService.listAnnotationLayer(Mockito.isNull())) + .thenReturn(asList(relationLayer)); - relationLayer.setType(WebAnnoConst.CHAIN_TYPE); - Mockito.when(annotationService.listAnnotationLayer(Mockito.isNull())) - .thenReturn(Arrays.asList(relationLayer)); - - JCas jcas = JCasFactory.createJCas(); + var jcas = createJCas(); jcas.setDocumentText("This is a test."); - Token spanThis = new Token(jcas, 0, 4); + var spanThis = new Token(jcas, 0, 4); spanThis.addToIndexes(); - Token spanIs = new Token(jcas, 6, 8); + var spanIs = new Token(jcas, 6, 8); spanIs.addToIndexes(); - Token spanA = new Token(jcas, 9, 10); + var spanA = new Token(jcas, 9, 10); spanA.addToIndexes(); - Dependency dep1 = new Dependency(jcas, 0, 8); + var dep1 = new Dependency(jcas, 0, 8); dep1.setGovernor(spanThis); dep1.setDependent(spanIs); dep1.addToIndexes(); - Dependency dep2 = new Dependency(jcas, 0, 10); + var dep2 = new Dependency(jcas, 0, 10); dep2.setGovernor(spanA); dep2.setDependent(spanIs); dep2.addToIndexes(); - List messages = new ArrayList<>(); + var messages = new ArrayList(); - boolean result = sut.check(null, jcas.getCas(), messages); + var result = sut.check(document, dataOwner, jcas.getCas(), messages); messages.forEach(System.out::println); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheckTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheckTest.java index 14a74c93d3f..9e35f9360b6 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheckTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/checks/TokensAndSententencedDoNotOverlapCheckTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; @@ -36,14 +36,15 @@ class TokensAndSententencedDoNotOverlapCheckTest { TokensAndSententencedDoNotOverlapCheck sut; - Project project; + SourceDocument document; + String dataOwner; JCas jCas; @BeforeEach void setup() throws Exception { sut = new TokensAndSententencedDoNotOverlapCheck(); - project = new Project(); + document = SourceDocument.builder().build(); jCas = JCasFactory.createJCas(); } @@ -60,7 +61,7 @@ void thatOverlappingSentencesFailCheck() var messages = new ArrayList(); - var result = sut.check(project, jCas.getCas(), messages); + var result = sut.check(document, dataOwner, jCas.getCas(), messages); assertThat(result).isFalse(); assertThat(messages).hasSize(1); @@ -81,7 +82,7 @@ void thatOverlappingTokensFailCheck() var messages = new ArrayList(); - var result = sut.check(project, jCas.getCas(), messages); + var result = sut.check(document, dataOwner, jCas.getCas(), messages); assertThat(result).isFalse(); assertThat(messages).hasSize(1); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepairTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepairTest.java index 365b627bb6c..2352c0ea4ae 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepairTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/CoverAllTextInSentencesRepairTest.java @@ -29,21 +29,22 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; class CoverAllTextInSentencesRepairTest { CoverAllTextInSentencesRepair sut; - Project project; + SourceDocument document; + String dataOwner; JCas jCas; @BeforeEach void setup() throws Exception { sut = new CoverAllTextInSentencesRepair(); - project = new Project(); + document = SourceDocument.builder().build(); jCas = JCasFactory.createJCas(); } @@ -59,7 +60,7 @@ void thatNewSentenceIsAddedOnText() var messages = new ArrayList(); - sut.repair(project, jCas.getCas(), messages); + sut.repair(document, dataOwner, jCas.getCas(), messages); assertThat(jCas.select(Sentence.class).asList()) // .extracting(Annotation::getBegin, Annotation::getEnd) @@ -81,7 +82,7 @@ void thatNoNewSentenceIsAddedOnBlank() var messages = new ArrayList(); - sut.repair(project, jCas.getCas(), messages); + sut.repair(document, dataOwner, jCas.getCas(), messages); assertThat(jCas.select(Sentence.class).asList()) // .extracting(Annotation::getBegin, Annotation::getEnd) @@ -101,7 +102,7 @@ void thatNewSentenceIsAddedAtDocumentStart() var messages = new ArrayList(); - sut.repair(project, jCas.getCas(), messages); + sut.repair(document, dataOwner, jCas.getCas(), messages); assertThat(jCas.select(Sentence.class).asList()) // .extracting(Annotation::getBegin, Annotation::getEnd) @@ -122,7 +123,7 @@ void thatNewSentenceIsAddedAtDocumentEnd() var messages = new ArrayList(); - sut.repair(project, jCas.getCas(), messages); + sut.repair(document, dataOwner, jCas.getCas(), messages); assertThat(jCas.select(Sentence.class).asList()) // .extracting(Annotation::getBegin, Annotation::getEnd) diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepairTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepairTest.java index 4d4aab9d4df..c6e2207b29d 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepairTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveBomRepairTest.java @@ -59,7 +59,7 @@ void test() throws Exception } var messages = new ArrayList(); - sut.repair(null, cas, messages); + sut.repair(null, null, cas, messages); assertThat(annotations).hasSizeGreaterThan(annotationCount); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepairTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepairTest.java index 2ad73144b15..798e5ca1203 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepairTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/RemoveDanglingRelationsRepairTest.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import org.apache.uima.fit.factory.JCasFactory; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -37,6 +38,8 @@ import de.tudarmstadt.ukp.clarin.webanno.diag.ChecksRegistryImpl; import de.tudarmstadt.ukp.clarin.webanno.diag.RepairsRegistryImpl; import de.tudarmstadt.ukp.clarin.webanno.diag.checks.AllFeatureStructuresIndexedCheck; +import de.tudarmstadt.ukp.clarin.webanno.model.Project; +import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.dependency.Dependency; import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationAdapter; @@ -49,6 +52,19 @@ public class RemoveDanglingRelationsRepairTest private @Mock ConstraintsService constraintsService; private @Mock AnnotationSchemaService schemaService; + Project project; + SourceDocument document; + String dataOwner; + + @BeforeEach + void setup() throws Exception + { + project = Project.builder().build(); + document = SourceDocument.builder() // + .withProject(project) // + .build(); + } + @Test public void test() throws Exception { @@ -84,10 +100,10 @@ public void test() throws Exception .toArray(String[]::new)); // A project is not required for this check - var result = cd.analyze(null, jcas.getCas(), messages); + var result = cd.analyze(null, null, jcas.getCas(), messages); // A project is not required for this repair - cd.repair(null, jcas.getCas(), messages); + cd.repair(document, dataOwner, jcas.getCas(), messages); assertFalse(result); diff --git a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepairTest.java b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepairTest.java index 20d34658544..a7319fc3a69 100644 --- a/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepairTest.java +++ b/inception/inception-diag/src/test/java/de/tudarmstadt/ukp/clarin/webanno/diag/repairs/SwitchBeginAndEndOnNegativeSizedAnnotationsRepairTest.java @@ -29,21 +29,18 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.inception.support.logging.LogMessage; class SwitchBeginAndEndOnNegativeSizedAnnotationsRepairTest { SwitchBeginAndEndOnNegativeSizedAnnotationsRepair sut; - Project project; JCas jCas; @BeforeEach void setup() throws Exception { sut = new SwitchBeginAndEndOnNegativeSizedAnnotationsRepair(); - project = new Project(); jCas = JCasFactory.createJCas(); } @@ -58,7 +55,7 @@ void test() var messages = new ArrayList(); - sut.repair(project, jCas.getCas(), messages); + sut.repair(null, null, jCas.getCas(), messages); assertThat(jCas.select(Token.class).asList()) // .extracting(Annotation::getBegin, Annotation::getEnd) diff --git a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/DocumentImportExportServiceImpl.java b/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/DocumentImportExportServiceImpl.java index 2fb672975db..1cad67806fc 100644 --- a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/DocumentImportExportServiceImpl.java +++ b/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/DocumentImportExportServiceImpl.java @@ -21,6 +21,7 @@ import static de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasAccessMode.UNMANAGED_ACCESS; import static de.tudarmstadt.ukp.inception.project.api.ProjectService.withProjectLogger; import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.CURATION_USER; +import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.INITIAL_CAS_PSEUDO_USER; import static de.tudarmstadt.ukp.inception.support.uima.WebAnnoCasUtil.exists; import static de.tudarmstadt.ukp.inception.support.uima.WebAnnoCasUtil.getRealCas; import static java.util.Arrays.asList; @@ -363,11 +364,10 @@ private void runCasDoctorOnImport(SourceDocument aDocument, FormatSupport aForma var casDoctor = new CasDoctor(checksRegistry, repairsRegistry); casDoctor.setActiveChecks( checksRegistry.getExtensions().stream().map(c -> c.getId()).toArray(String[]::new)); - casDoctor.analyze(aDocument.getProject(), aCas, messages, true); + casDoctor.analyze(aDocument, INITIAL_CAS_PSEUDO_USER, aCas, messages, true); } - private void splitTokens(CAS cas, FormatSupport aFormat) - throws IOException + private void splitTokens(CAS cas, FormatSupport aFormat) throws IOException { var tokenType = getType(cas, Token.class); @@ -396,8 +396,7 @@ private void checkTokenQuota(CAS cas, FormatSupport aFormat) throws IOException } } - private void splitSenencesIfNecssary(CAS cas, FormatSupport aFormat) - throws IOException + private void splitSenencesIfNecssary(CAS cas, FormatSupport aFormat) throws IOException { var sentenceType = getType(cas, Sentence.class); diff --git a/inception/inception-io-xml/src/main/java/de/tudarmstadt/ukp/inception/io/xml/dkprocore/XmlNodeUtils.java b/inception/inception-io-xml/src/main/java/de/tudarmstadt/ukp/inception/io/xml/dkprocore/XmlNodeUtils.java index b2809d3e3d8..18eabf09230 100644 --- a/inception/inception-io-xml/src/main/java/de/tudarmstadt/ukp/inception/io/xml/dkprocore/XmlNodeUtils.java +++ b/inception/inception-io-xml/src/main/java/de/tudarmstadt/ukp/inception/io/xml/dkprocore/XmlNodeUtils.java @@ -33,16 +33,19 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; +import org.apache.uima.cas.CAS; +import org.apache.uima.cas.FeatureStructure; import org.apache.uima.jcas.JCas; +import org.apache.uima.util.CasCopier; import org.dkpro.core.api.xml.type.XmlAttribute; +import org.dkpro.core.api.xml.type.XmlDocument; import org.dkpro.core.api.xml.type.XmlElement; import org.dkpro.core.api.xml.type.XmlNode; import org.dkpro.core.api.xml.type.XmlTextNode; @@ -61,8 +64,8 @@ public static boolean hasAttributeWithValue(XmlElement e, String aAttribute, Str static String serializeCasToXmlString(JCas aJCas) throws IOException { try (var out = new StringWriter()) { - SAXTransformerFactory tf = XmlParserUtils.newTransformerFactory(); - TransformerHandler th = tf.newTransformerHandler(); + var tf = XmlParserUtils.newTransformerFactory(); + var th = tf.newTransformerHandler(); th.getTransformer().setOutputProperty(OMIT_XML_DECLARATION, "yes"); th.getTransformer().setOutputProperty(METHOD, "xml"); th.getTransformer().setOutputProperty(INDENT, "no"); @@ -87,7 +90,7 @@ static void parseXmlStringToCas(JCas aJCas, String aXml) throws IOException static void parseXmlToCas(JCas aJCas, InputSource aSource) throws IOException { - CasXmlHandler handler = new CasXmlHandler(aJCas); + var handler = new CasXmlHandler(aJCas); try { var parser = XmlParserUtils.newSaxParser(); @@ -278,4 +281,30 @@ public static List rootPath(XmlElement aElement) return path; } + public static int transferXmlDocumentStructure(CAS aTarget, CAS aSource) + { + var copied = new AtomicInteger(); + var casCopier = new CasCopier(aSource, aTarget); + Consumer copyFunc = fs -> { + var copy = casCopier.copyFs(fs); + if (copy != null) { + copied.incrementAndGet(); + aTarget.addFsToIndexes(copy); + } + }; + + aSource.select(XmlDocument.class).forEach(copyFunc); + aSource.select(XmlNode.class).forEach(copyFunc); + return copied.get(); + } + + public static int removeXmlDocumentStructure(CAS aCas) + { + var toDelete = new ArrayList(); + aCas.select(XmlDocument.class).forEach(toDelete::add); + aCas.select(XmlNode.class).forEach(toDelete::add); + aCas.select(XmlAttribute.class).forEach(toDelete::add); + toDelete.forEach(aCas::removeFsFromIndexes); + return toDelete.size(); + } } diff --git a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/CheckTask.java b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/CheckTask.java index 858f3988a3e..8e2bbef5215 100644 --- a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/CheckTask.java +++ b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/CheckTask.java @@ -104,7 +104,8 @@ public void execute() casStorageService.forceActionOnCas(sd, INITIAL_CAS_PSEUDO_USER, (doc, user) -> createOrReadInitialCasWithoutSavingOrChecks(doc, messageSet), - (cas) -> casDoctor.analyze(project, cas, messageSet.getMessages()), // + (doc, user, cas) -> casDoctor.analyze(doc, user, cas, + messageSet.getMessages()), // false); } catch (Exception e) { @@ -126,7 +127,8 @@ public void execute() casStorageService.forceActionOnCas(sd, CURATION_USER, (doc, user) -> casStorageService.readCas(doc, user, UNMANAGED_NON_INITIALIZING_ACCESS), - (cas) -> casDoctor.analyze(project, cas, messageSet.getMessages()), // + (doc, user, cas) -> casDoctor.analyze(doc, user, cas, + messageSet.getMessages()), // false); } catch (FileNotFoundException e) { @@ -156,7 +158,8 @@ public void execute() casStorageService.forceActionOnCas(ad.getDocument(), ad.getUser(), (doc, user) -> casStorageService.readCas(doc, user, UNMANAGED_NON_INITIALIZING_ACCESS), - (cas) -> casDoctor.analyze(project, cas, messageSet.getMessages()), // + (doc, user, cas) -> casDoctor.analyze(doc, user, cas, + messageSet.getMessages()), // false); } } diff --git a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/RepairTask.java b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/RepairTask.java index 407b2a3746a..32fed7f8abf 100644 --- a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/RepairTask.java +++ b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/casdoctor/RepairTask.java @@ -104,7 +104,8 @@ public void execute() casStorageService.forceActionOnCas(sd, INITIAL_CAS_PSEUDO_USER, (doc, user) -> createOrReadInitialCasWithoutSavingOrChecks(doc, messageSet), - (cas) -> casDoctor.repair(project, cas, messageSet.getMessages()), // + (doc, user, cas) -> casDoctor.repair(doc, user, cas, + messageSet.getMessages()), // true); } catch (Exception e) { @@ -125,7 +126,8 @@ public void execute() casStorageService.forceActionOnCas(sd, CURATION_USER, (doc, user) -> casStorageService.readCas(doc, user, UNMANAGED_NON_INITIALIZING_ACCESS), - (cas) -> casDoctor.repair(project, cas, messageSet.getMessages()), // + (doc, user, cas) -> casDoctor.repair(doc, user, cas, + messageSet.getMessages()), // true); } catch (FileNotFoundException e) { @@ -158,7 +160,8 @@ public void execute() casStorageService.forceActionOnCas(sd, ad.getUser(), (doc, user) -> casStorageService.readCas(doc, user, UNMANAGED_NON_INITIALIZING_ACCESS), - (cas) -> casDoctor.repair(project, cas, messageSet.getMessages()), // + (doc, user, cas) -> casDoctor.repair(doc, user, cas, + messageSet.getMessages()), // true); } } From 437e3ff9c8b832d33c494d5dd0f547ab34b77547 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Tue, 15 Oct 2024 10:21:33 +0200 Subject: [PATCH 5/6] [maven-release-plugin] prepare release inception-34.1 --- inception/inception-active-learning/pom.xml | 2 +- inception/inception-agreement/pom.xml | 2 +- .../inception-annotation-storage-api/pom.xml | 2 +- .../inception-annotation-storage/pom.xml | 2 +- inception/inception-api-annotation/pom.xml | 2 +- inception/inception-api-editor/pom.xml | 2 +- inception/inception-api-formats/pom.xml | 2 +- inception/inception-api-render/pom.xml | 2 +- inception/inception-app-webapp/pom.xml | 2 +- inception/inception-bom/pom.xml | 254 +++++++++--------- inception/inception-boot-loader/pom.xml | 2 +- inception/inception-brat-editor/pom.xml | 2 +- inception/inception-build/pom.xml | 2 +- inception/inception-concept-linking/pom.xml | 2 +- inception/inception-constraints/pom.xml | 2 +- inception/inception-curation-legacy/pom.xml | 2 +- inception/inception-curation/pom.xml | 2 +- inception/inception-dependencies/pom.xml | 2 +- inception/inception-diag/pom.xml | 2 +- inception/inception-diam-api/pom.xml | 2 +- inception/inception-diam-compactv2/pom.xml | 2 +- inception/inception-diam-editor/pom.xml | 2 +- inception/inception-diam/pom.xml | 2 +- inception/inception-doc/pom.xml | 2 +- inception/inception-docker/pom.xml | 2 +- inception/inception-documents-api/pom.xml | 2 +- inception/inception-documents/pom.xml | 2 +- .../pom.xml | 2 +- inception/inception-export-api/pom.xml | 2 +- inception/inception-export/pom.xml | 2 +- inception/inception-external-editor/pom.xml | 2 +- .../inception-external-search-core/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../inception-external-search-pubmed/pom.xml | 2 +- .../inception-external-search-solr/pom.xml | 2 +- inception/inception-feature-lookup/pom.xml | 2 +- inception/inception-guidelines/pom.xml | 2 +- .../pom.xml | 2 +- inception/inception-html-editor/pom.xml | 2 +- .../inception-html-recogito-editor/pom.xml | 2 +- inception/inception-image/pom.xml | 2 +- .../inception-imls-azureai-openai/pom.xml | 2 +- inception/inception-imls-chatgpt/pom.xml | 2 +- inception/inception-imls-elg/pom.xml | 2 +- inception/inception-imls-external/pom.xml | 2 +- inception/inception-imls-hf/pom.xml | 2 +- inception/inception-imls-lapps/pom.xml | 2 +- inception/inception-imls-ollama/pom.xml | 2 +- inception/inception-imls-opennlp/pom.xml | 2 +- inception/inception-imls-stringmatch/pom.xml | 2 +- inception/inception-imls-support-llm/pom.xml | 2 +- inception/inception-imls-weblicht/pom.xml | 2 +- inception/inception-io-bioc/pom.xml | 2 +- inception/inception-io-brat/pom.xml | 2 +- inception/inception-io-conll/pom.xml | 2 +- inception/inception-io-html/pom.xml | 2 +- inception/inception-io-imscwb/pom.xml | 2 +- inception/inception-io-intertext/pom.xml | 2 +- inception/inception-io-json/pom.xml | 2 +- inception/inception-io-lif/pom.xml | 2 +- inception/inception-io-nif/pom.xml | 2 +- inception/inception-io-perseus/pom.xml | 2 +- inception/inception-io-rdf/pom.xml | 2 +- inception/inception-io-tcf/pom.xml | 2 +- inception/inception-io-tei/pom.xml | 2 +- inception/inception-io-text/pom.xml | 2 +- inception/inception-io-webanno-tsv/pom.xml | 2 +- inception/inception-io-xmi/pom.xml | 2 +- inception/inception-io-xml/pom.xml | 2 +- inception/inception-js-api/pom.xml | 2 +- inception/inception-kb-fact-linking/pom.xml | 2 +- inception/inception-kb-lucene-sail/pom.xml | 2 +- inception/inception-kb/pom.xml | 2 +- inception/inception-layer-docmetadata/pom.xml | 2 +- inception/inception-log-ui/pom.xml | 2 +- inception/inception-log/pom.xml | 2 +- inception/inception-model-export/pom.xml | 2 +- inception/inception-model-vdoc/pom.xml | 2 +- inception/inception-model/pom.xml | 2 +- inception/inception-pdf-editor/pom.xml | 2 +- inception/inception-pdf-editor2/pom.xml | 2 +- inception/inception-plugin-api/pom.xml | 2 +- inception/inception-plugin-manager/pom.xml | 2 +- inception/inception-plugin-parent/pom.xml | 2 +- inception/inception-preferences/pom.xml | 2 +- inception/inception-processing/pom.xml | 2 +- inception/inception-project-api/pom.xml | 2 +- inception/inception-project-export/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../inception-project-initializers-ud/pom.xml | 2 +- .../pom.xml | 2 +- .../inception-project-initializers/pom.xml | 2 +- inception/inception-project/pom.xml | 2 +- .../inception-recommendation-api/pom.xml | 2 +- inception/inception-recommendation/pom.xml | 2 +- inception/inception-remote/pom.xml | 2 +- inception/inception-review-editor/pom.xml | 2 +- inception/inception-scheduling/pom.xml | 2 +- inception/inception-schema-api/pom.xml | 2 +- inception/inception-schema/pom.xml | 2 +- inception/inception-search-core/pom.xml | 2 +- .../inception-search-mtas-upstream/pom.xml | 2 +- inception/inception-search-mtas/pom.xml | 2 +- inception/inception-security/pom.xml | 2 +- inception/inception-sharing/pom.xml | 2 +- inception/inception-support-bootstrap/pom.xml | 2 +- .../inception-support-standalone/pom.xml | 2 +- inception/inception-support/pom.xml | 2 +- inception/inception-telemetry/pom.xml | 2 +- inception/inception-test-dependencies/pom.xml | 2 +- inception/inception-testing/pom.xml | 2 +- inception/inception-tutorial/pom.xml | 2 +- inception/inception-ui-agreement/pom.xml | 2 +- inception/inception-ui-annotation/pom.xml | 2 +- inception/inception-ui-core/pom.xml | 2 +- inception/inception-ui-curation/pom.xml | 2 +- .../inception-ui-dashboard-activity/pom.xml | 2 +- inception/inception-ui-dashboard/pom.xml | 2 +- .../inception-ui-external-search/pom.xml | 2 +- inception/inception-ui-kb/pom.xml | 2 +- inception/inception-ui-project/pom.xml | 2 +- inception/inception-ui-scheduling/pom.xml | 2 +- inception/inception-ui-search/pom.xml | 2 +- inception/inception-ui-tagsets/pom.xml | 2 +- inception/inception-versioning/pom.xml | 2 +- inception/inception-websocket/pom.xml | 2 +- inception/inception-workload-dynamic/pom.xml | 2 +- inception/inception-workload-matrix/pom.xml | 2 +- inception/inception-workload-ui/pom.xml | 2 +- inception/inception-workload/pom.xml | 2 +- inception/pom.xml | 6 +- pom.xml | 4 +- 136 files changed, 265 insertions(+), 265 deletions(-) diff --git a/inception/inception-active-learning/pom.xml b/inception/inception-active-learning/pom.xml index a5cc0d8c11f..0ae438aa9e9 100644 --- a/inception/inception-active-learning/pom.xml +++ b/inception/inception-active-learning/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 .. inception-active-learning diff --git a/inception/inception-agreement/pom.xml b/inception/inception-agreement/pom.xml index 688f712606e..709551f528b 100644 --- a/inception/inception-agreement/pom.xml +++ b/inception/inception-agreement/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-agreement diff --git a/inception/inception-annotation-storage-api/pom.xml b/inception/inception-annotation-storage-api/pom.xml index 961d76fff45..7924da5c92e 100644 --- a/inception/inception-annotation-storage-api/pom.xml +++ b/inception/inception-annotation-storage-api/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-annotation-storage-api INCEpTION - Core - Annotation Storage - API diff --git a/inception/inception-annotation-storage/pom.xml b/inception/inception-annotation-storage/pom.xml index 88051bde133..0006ccfa035 100644 --- a/inception/inception-annotation-storage/pom.xml +++ b/inception/inception-annotation-storage/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-annotation-storage INCEpTION - Core - Annotation Storage diff --git a/inception/inception-api-annotation/pom.xml b/inception/inception-api-annotation/pom.xml index 7203bea8abf..770bcf7b2ba 100644 --- a/inception/inception-api-annotation/pom.xml +++ b/inception/inception-api-annotation/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-api-annotation INCEpTION - Core - Annotation API diff --git a/inception/inception-api-editor/pom.xml b/inception/inception-api-editor/pom.xml index abd27ceed38..fc007965831 100644 --- a/inception/inception-api-editor/pom.xml +++ b/inception/inception-api-editor/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-api-editor INCEpTION - Core - Annotation editor API diff --git a/inception/inception-api-formats/pom.xml b/inception/inception-api-formats/pom.xml index 49e8e08a54b..2755068a6d2 100644 --- a/inception/inception-api-formats/pom.xml +++ b/inception/inception-api-formats/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-api-formats INCEpTION - Core - Formats API diff --git a/inception/inception-api-render/pom.xml b/inception/inception-api-render/pom.xml index 1987d8ac534..10c6ba45111 100644 --- a/inception/inception-api-render/pom.xml +++ b/inception/inception-api-render/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 inception-api-render INCEpTION - Core - Annotation rendering API diff --git a/inception/inception-app-webapp/pom.xml b/inception/inception-app-webapp/pom.xml index d4e44ee57ab..78aba92c1cb 100644 --- a/inception/inception-app-webapp/pom.xml +++ b/inception/inception-app-webapp/pom.xml @@ -21,7 +21,7 @@ de.tudarmstadt.ukp.inception.app inception-app - 34.1-SNAPSHOT + 34.1 .. diff --git a/inception/inception-bom/pom.xml b/inception/inception-bom/pom.xml index 943b92d7c5a..719341d1ebd 100644 --- a/inception/inception-bom/pom.xml +++ b/inception/inception-bom/pom.xml @@ -20,7 +20,7 @@ de.tudarmstadt.ukp.inception.app inception - 34.1-SNAPSHOT + 34.1 ../../pom.xml @@ -33,237 +33,237 @@ de.tudarmstadt.ukp.inception.app inception-doc - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-agreement - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-agreement - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-annotation - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-project - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-tagsets - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-curation - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-curation - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-search - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-workload - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-workload-dynamic - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-workload-matrix - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-workload-ui - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-external-editor - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-external-search-core - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-external-search-pubannotation - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-external-search-pubmed - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-external-search-opensearch - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-external-search-solr - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-external-search - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-dashboard - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-dashboard-activity - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-kb - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-kb-fact-linking - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-kb-lucene-sail - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-html-apache-annotator-editor - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-html-editor - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-html-recogito-editor - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-pdf-editor - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-pdf-editor2 - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-recommendation - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-recommendation-api - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-review-editor - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-sharing - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-preferences - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-processing - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-guidelines - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-schema - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-active-learning - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-core - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-ui-kb - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-concept-linking - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-imls-azureai-openai - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-imls-chatgpt - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-imls-opennlp - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-imls-elg - 34.1-SNAPSHOT + 34.1 de.tudarmstadt.ukp.inception.app inception-imls-hf - 34.1-SNAPSHOT + 34.1