/** * Copy this same annotation from the user annotation to the mergeview */ private static void copySpanAnnotation(AnnotatorState aState, AnnotationSchemaService aAnnotationService, AnnotationLayer aAnnotationLayer, AnnotationFS aOldFs, JCas aJCas) throws AnnotationException { SpanAdapter adapter = (SpanAdapter) aAnnotationService.getAdapter(aAnnotationLayer); // Create the annotation - this also takes care of attaching to an annotation if necessary int id = getAddr(adapter.add(aState.getDocument(), aState.getUser().getUsername(), aJCas, aOldFs.getBegin(), aOldFs.getEnd())); List<AnnotationFeature> features = aAnnotationService .listAnnotationFeature(adapter.getLayer()); // Copy the features for (AnnotationFeature feature : features) { Type oldType = adapter.getAnnotationType(aOldFs.getCAS()); Feature oldFeature = oldType.getFeatureByBaseName(feature.getName()); if (isLinkOrBasicFeatures(aOldFs, oldFeature)) { continue; } Object value = adapter.getFeatureValue(feature, aOldFs); adapter.setFeatureValue(aState.getDocument(), aState.getUser().getUsername(), aJCas, id, feature, value); } }
@Override public int upsertFeature(AnnotationSchemaService annotationService, SourceDocument aDocument, String aUsername, JCas aJCas, AnnotationLayer layer, AnnotationFeature aFeature, String aValue, int aBegin, int aEnd) throws AnnotationException { // The feature of the predicted label SpanAdapter adapter = (SpanAdapter) annotationService.getAdapter(layer); // Check if there is already an annotation of the target type at the given location Type type = CasUtil.getType(aJCas.getCas(), adapter.getAnnotationTypeName()); AnnotationFS annoFS = selectSingleFsAt(aJCas, type, aBegin, aEnd); int address; if (annoFS != null) { // ... if yes, then we update the feature on the existing annotation address = getAddr(annoFS); } else { // ... if not, then we create a new annotation - this also takes care of attaching to // an annotation if necessary address = getAddr(adapter.add(aDocument, aUsername, aJCas, aBegin, aEnd)); } // Update the feature value adapter.setFeatureValue(aDocument, aUsername, aJCas, address, aFeature, aValue); return address; }
@Override public SpanAdapter createAdapter(AnnotationLayer aLayer) { SpanAdapter adapter = new SpanAdapter(featureSupportRegistry, eventPublisher, aLayer, schemaService.listAnnotationFeature(aLayer), layerBehaviorsRegistry.getLayerBehaviors(this, SpanLayerBehavior.class)); return adapter; }
/** * A Helper method to add annotation to CAS */ private AnnotationFS createSpanAnnotation(CAS aCas, int aBegin, int aEnd) throws AnnotationException { Type type = CasUtil.getType(aCas, getAnnotationTypeName()); AnnotationFS newAnnotation = aCas.createAnnotation(type, aBegin, aEnd); // If if the layer attaches to a feature, then set the attach-feature to the newly // created annotation. if (getAttachFeatureName() != null) { Type theType = CasUtil.getType(aCas, getAttachTypeName()); Feature attachFeature = theType.getFeatureByBaseName(getAttachFeatureName()); if (CasUtil.selectCovered(aCas, theType, aBegin, aEnd).isEmpty()) { throw new AnnotationException("No annotation of type [" + getAttachTypeName() + "] to attach to at location [" + aBegin + "-" + aEnd + "]."); } CasUtil.selectCovered(aCas, theType, aBegin, aEnd).get(0) .setFeatureValue(attachFeature, newAnnotation); } aCas.addFsToIndexes(newAnnotation); return newAnnotation; }
@Override public void delete(SourceDocument aDocument, String aUsername, JCas aJCas, VID aVid) { AnnotationFS fs = selectByAddr(aJCas, AnnotationFS.class, aVid.getId()); aJCas.removeFsFromIndexes(fs); // delete associated attachFeature if (getAttachTypeName() != null) { Type theType = CasUtil.getType(aJCas.getCas(), getAttachTypeName()); Feature attachFeature = theType.getFeatureByBaseName(getAttachFeatureName()); if (attachFeature != null) { CasUtil.selectCovered(aJCas.getCas(), theType, fs.getBegin(), fs.getEnd()).get(0) .setFeatureValue(attachFeature, null); } } publishEvent(new SpanDeletedEvent(this, aDocument, aUsername, getLayer(), fs)); }
Type type = getType(aJcas.getCas(), typeAdapter.getAnnotationTypeName()); List<AnnotationFS> annotations = selectCovered(aJcas.getCas(), type, aWindowBegin, aWindowEnd); aWindowBegin, aWindowEnd, fs); VSpan span = new VSpan(typeAdapter.getLayer(), fs, bratTypeName, ranges, features, hoverFeatures); for (AnnotationFeature feat : typeAdapter.listFeatures()) { if (MultiValueMode.ARRAY.equals(feat.getMultiValueMode()) && LinkMode.WITH_ROLE.equals(feat.getLinkMode())) { List<LinkWithRoleModel> links = typeAdapter.getFeatureValue(feat, fs); for (int li = 0; li < links.size(); li++) { LinkWithRoleModel link = links.get(li); FeatureStructure targetFS = selectByAddr(fs.getCAS(), link.targetAddr); aResponse.add(new VArc(typeAdapter.getLayer(), new VID(fs, fi, li), bratTypeName, fs, targetFS, link.role, features));
@Test public void thatSpanAnchoringAndStackingBehaviorsWorkInConcert() throws AnnotationException { TokenBuilder<Token, Sentence> builder = new TokenBuilder<>(Token.class, Sentence.class); builder.buildTokens(jcas, "This is a test ."); SpanAdapter sut = new SpanAdapter(featureSupportRegistry, null, neLayer, asList(), behaviors); // First time should work - we annotate the whole word "This" sut.add(document, username, jcas, 0, 4); // Second time not - here we annotate "T" but it should be expanded to "This" assertThatExceptionOfType(AnnotationException.class) .isThrownBy(() -> sut.add(document, username, jcas, 0, 1)) .withMessageContaining("stacking is not enabled"); } }
AnnotationLayer layer = aAdapter.getLayer(); selection.getEnd() }); Type type = CasUtil.getType(aJCas.getCas(), aAdapter.getAnnotationTypeName()); for (AnnotationFS fs : selectCovered(aJCas.getCas(), type, adjustedRange[0], adjustedRange[1])) { if (fs.getBegin() == selection.getBegin() && fs.getEnd() == selection.getEnd()) { spanValue = aAdapter.getFeatureValue(featureState.feature, fs);
@Test public void thatSpanStackingBehaviorOnValidateGeneratesErrors() throws AnnotationException { TokenBuilder<Token, Sentence> builder = new TokenBuilder<>(Token.class, Sentence.class); builder.buildTokens(jcas, "This is a test ."); SpanAdapter sut = new SpanAdapter(featureSupportRegistry, null, neLayer, asList(), behaviors); // Add two annotations neLayer.setAllowStacking(true); sut.add(document, username, jcas, 0, 1); sut.add(document, username, jcas, 0, 1); //Validation fails neLayer.setAllowStacking(false); assertThat(sut.validate(jcas)) .extracting(Pair::getLeft) .usingElementComparatorIgnoringFields("source", "message") .containsExactly(LogMessage.error(null, "")); }
if (selectCovered(jCas, Token.class, sentence.getBegin() + i, sentence.getBegin() + i + selectedText.length()).size() > 0) { int addr = getAddr(adapter.add(aState.getDocument(), aState.getUser().getUsername(), jCas, sentence.getBegin() + i, sentence.getBegin() + i + selectedText.length() - 1)); adapter.setFeatureValue(aState.getDocument(), aState.getUser().getUsername(), jCas, addr, aFeature, aValue);
private void createNewSpanAnnotation(AjaxRequestTarget aTarget, SpanAdapter aAdapter, JCas aJCas) throws IOException, AnnotationException { handleForwardAnnotation(aTarget, aAdapter, aJCas); AnnotatorState state = getModelObject(); Selection selection = state.getSelection(); AnnotationFS annoFs = aAdapter.add(state.getDocument(), state.getUser().getUsername(), aJCas, selection.getBegin(), selection.getEnd()); selection.selectSpan(new VID(annoFs), aJCas, annoFs.getBegin(), annoFs.getEnd()); }
LinkWithRoleModel linkRole = null; int fi = 0; f: for (AnnotationFeature feat : aAdapter.listFeatures()) { if (MultiValueMode.ARRAY.equals(feat.getMultiValueMode()) && LinkMode.WITH_ROLE.equals(feat.getLinkMode())) { List<LinkWithRoleModel> links = aAdapter.getFeatureValue(feat, aClickedFS); for (int li = 0; li < links.size(); li++) { LinkWithRoleModel link = links.get(li); List<LinkWithRoleModel> links = aAdapter.getFeatureValue(slotFeature, mergeFs);
public static Map<Integer, String> getMultipleAnnotation( AnnotationSchemaService aAnnotationService, Sentence sentence, AnnotationFeature aFeature) throws CASException { SpanAdapter adapter = (SpanAdapter) aAnnotationService.getAdapter(aFeature.getLayer()); Map<Integer, String> multAnno = new HashMap<>(); Type type = getType(sentence.getCAS(), adapter.getAnnotationTypeName()); for (AnnotationFS fs : selectCovered(type, sentence)) { boolean isBegin = true; Feature labelFeature = fs.getType().getFeatureByBaseName(aFeature.getName()); for (Token token : selectCovered(Token.class, fs)) { if (multAnno.get(getAddr(token)) == null) { if (isBegin) { multAnno.put(getAddr(token), "B-" + fs.getFeatureValueAsString(labelFeature)); isBegin = false; } else { multAnno.put(getAddr(token), "I-" + fs.getFeatureValueAsString(labelFeature)); } } } } return multAnno; }
@Override public List<Pair<LogMessage, AnnotationFS>> validate(JCas aJCas) { List<Pair<LogMessage, AnnotationFS>> messages = new ArrayList<>(); for (SpanLayerBehavior behavior : behaviors) { long startTime = currentTimeMillis(); messages.addAll(behavior.onValidate(this, aJCas)); log.trace("Validation for [{}] on [{}] took {}ms", behavior.getClass().getSimpleName(), getLayer().getUiName(), currentTimeMillis() - startTime); } return messages; } }
Type type = getType(aJcas.getCas(), typeAdapter.getAnnotationTypeName()); List<AnnotationFS> annotations = selectCovered(aJcas.getCas(), type, aWindowBegin, aWindowEnd); aWindowBegin, aWindowEnd, fs); VSpan span = new VSpan(typeAdapter.getLayer(), fs, bratTypeName, ranges, features, hoverFeatures); for (AnnotationFeature feat : typeAdapter.listFeatures()) { if (MultiValueMode.ARRAY.equals(feat.getMultiValueMode()) && LinkMode.WITH_ROLE.equals(feat.getLinkMode())) { List<LinkWithRoleModel> links = typeAdapter.getFeatureValue(feat, fs); for (int li = 0; li < links.size(); li++) { LinkWithRoleModel link = links.get(li); FeatureStructure targetFS = selectByAddr(fs.getCAS(), link.targetAddr); aResponse.add(new VArc(typeAdapter.getLayer(), new VID(fs, fi, li), bratTypeName, fs, targetFS, link.role, features));
@Test public void thatSpanStackingBehaviorOnCreateThrowsException() throws AnnotationException { neLayer.setAllowStacking(false); TokenBuilder<Token, Sentence> builder = new TokenBuilder<>(Token.class, Sentence.class); builder.buildTokens(jcas, "This is a test ."); SpanAdapter sut = new SpanAdapter(featureSupportRegistry, null, neLayer, asList(), behaviors); // First time should work sut.add(document, username, jcas, 0, 1); // Second time not assertThatExceptionOfType(AnnotationException.class) .isThrownBy(() -> sut.add(document, username, jcas, 0, 1)) .withMessageContaining("stacking is not enabled"); }
@Test public void thatSpanCrossSentenceBehaviorOnValidateReturnsErrorMessage() throws AnnotationException { TokenBuilder<Token, Sentence> builder = new TokenBuilder<>(Token.class, Sentence.class); builder.buildTokens(jcas, "This is a test .\nThis is sentence two ."); SpanAdapter sut = new SpanAdapter(featureSupportRegistry, null, neLayer, asList(), behaviors); // Add two annotations neLayer.setCrossSentence(true); sut.add(document, username, jcas, 0, jcas.getDocumentText().length()); //Validation fails neLayer.setCrossSentence(false); assertThat(sut.validate(jcas)) .extracting(Pair::getLeft) .usingElementComparatorIgnoringFields("source", "message") .containsExactly(LogMessage.error(null, "")); }
if (selectCovered(jCas, Token.class, sentence.getBegin() + i, sentence.getBegin() + i + selectedText.length()).size() > 0) { int addr = getAddr(adapter.add(aState.getDocument(), aState.getUser().getUsername(), jCas, sentence.getBegin() + i, sentence.getBegin() + i + selectedText.length() - 1)); adapter.setFeatureValue(aState.getDocument(), aState.getUser().getUsername(), jCas, addr, aFeature, aValue);
@Override public void delete(SourceDocument aDocument, String aUsername, JCas aJCas, VID aVid) { AnnotationFS fs = selectByAddr(aJCas, AnnotationFS.class, aVid.getId()); aJCas.removeFsFromIndexes(fs); // delete associated attachFeature if (getAttachTypeName() != null) { Type theType = CasUtil.getType(aJCas.getCas(), getAttachTypeName()); Feature attachFeature = theType.getFeatureByBaseName(getAttachFeatureName()); if (attachFeature != null) { CasUtil.selectCovered(aJCas.getCas(), theType, fs.getBegin(), fs.getEnd()).get(0) .setFeatureValue(attachFeature, null); } } publishEvent(new SpanDeletedEvent(this, aDocument, aUsername, getLayer(), fs)); }
/** * A Helper method to add annotation to CAS */ private AnnotationFS createSpanAnnotation(CAS aCas, int aBegin, int aEnd) throws AnnotationException { Type type = CasUtil.getType(aCas, getAnnotationTypeName()); AnnotationFS newAnnotation = aCas.createAnnotation(type, aBegin, aEnd); // If if the layer attaches to a feature, then set the attach-feature to the newly // created annotation. if (getAttachFeatureName() != null) { Type theType = CasUtil.getType(aCas, getAttachTypeName()); Feature attachFeature = theType.getFeatureByBaseName(getAttachFeatureName()); if (CasUtil.selectCovered(aCas, theType, aBegin, aEnd).isEmpty()) { throw new AnnotationException("No annotation of type [" + getAttachTypeName() + "] to attach to at location [" + aBegin + "-" + aEnd + "]."); } CasUtil.selectCovered(aCas, theType, aBegin, aEnd).get(0) .setFeatureValue(attachFeature, newAnnotation); } aCas.addFsToIndexes(newAnnotation); return newAnnotation; }