SpanRenderer extends Renderer_ImplBase<SpanAdapter> { @Override public void render(CAS aCas, List<AnnotationFeature> aFeatures, VDocument aResponse, int aWindowBegin, int aWindowEnd) { SpanAdapter typeAdapter = getTypeAdapter(); Type type; try { type = getType(aCas, typeAdapter.getAnnotationTypeName()); } catch (IllegalArgumentException e) { return; } Map<AnnotationFS, VSpan> annoToSpanIdx = new HashMap<>(); List<AnnotationFS> annotations = selectCovered(aCas, type, aWindowBegin, aWindowEnd); for (AnnotationFS fs : annotations) { String uiTypeName = typeAdapter.getEncodedTypeName(); Map<String, String> features = renderLabelFeatureValues(typeAdapter, fs, aFeatures); Map<String, String> hoverFeatures = renderHoverFeatureValues(typeAdapter, fs, aFeatures); VRange range = new VRange(fs.getBegin() - aWindowBegin, fs.getEnd() - aWindowBegin); VSpan span = new VSpan(typeAdapter.getLayer(), fs, uiTypeName, range, features, hoverFeatures); span.addLazyDetails(getLazyDetails(typeAdapter, fs, aFeatures)); annoToSpanIdx.put(fs, span); aResponse.add(span); renderRequiredFeatureErrors(aFeatures, fs, aResponse); int fi = 0; nextFeature: for (AnnotationFeature feat : typeAdapter.listFeatures()) { if (!feat.isEnabled()) { continue nextFeature; } if (ARRAY.equals(feat.getMultiValueMode()) && 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 = selectFsByAddr(fs.getCAS(), link.targetAddr); aResponse.add(new VArc(typeAdapter.getLayer(), new VID(fs, fi, li), uiTypeName, fs, targetFS, link.role, features)); } } fi++; } } for (SpanLayerBehavior behavior : behaviors) { behavior.onRender(typeAdapter, aResponse, annoToSpanIdx, aWindowBegin, aWindowEnd); } } SpanRenderer(SpanAdapter aTypeAdapter, LayerSupportRegistry aLayerSupportRegistry,
            FeatureSupportRegistry aFeatureSupportRegistry, List<SpanLayerBehavior> aBehaviors); @Override void render(CAS aCas, List<AnnotationFeature> aFeatures,
            VDocument aResponse, int aWindowBegin, int aWindowEnd);  }
@Test public void thatSpanCrossSentenceBehaviorOnRenderGeneratesErrors() { neLayer.setCrossSentence(false); jcas.setDocumentText(StringUtils.repeat("a", 20)); new Sentence(jcas, 0, 10).addToIndexes(); new Sentence(jcas, 10, 20).addToIndexes(); NamedEntity ne = new NamedEntity(jcas, 5, 15); ne.addToIndexes(); SpanAdapter adapter = new SpanAdapter(layerSupportRegistry, featureSupportRegistry, null, neLayer, () -> asList(), asList(new SpanCrossSentenceBehavior())); SpanRenderer sut = new SpanRenderer(adapter, layerSupportRegistry, featureSupportRegistry, asList(new SpanCrossSentenceBehavior())); VDocument vdoc = new VDocument(); sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length()); assertThat(vdoc.comments()) .usingFieldByFieldElementComparator() .containsExactlyInAnyOrder(new VComment(ne, VCommentType.ERROR, "Crossing sentence boundaries is not permitted.")); }
@Test public void thatSpanOverlapBehaviorOnRenderGeneratesErrors() { jcas.setDocumentText(StringUtils.repeat("a", 10)); new Sentence(jcas, 0, 10).addToIndexes(); NamedEntity ne1 = new NamedEntity(jcas, 3, 8); ne1.addToIndexes(); NamedEntity ne2 = new NamedEntity(jcas, 3, 8); ne2.addToIndexes(); SpanAdapter adapter = new SpanAdapter(layerSupportRegistry, featureSupportRegistry, null, neLayer, () -> asList(), asList(new SpanOverlapBehavior())); SpanRenderer sut = new SpanRenderer(adapter, layerSupportRegistry, featureSupportRegistry, asList(new SpanOverlapBehavior())); { neLayer.setOverlapMode(OverlapMode.NO_OVERLAP); VDocument vdoc = new VDocument(); sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length()); assertThat(vdoc.comments()) .usingFieldByFieldElementComparator() .containsExactlyInAnyOrder( new VComment(ne1, VCommentType.ERROR, "Stacking is not permitted."), new VComment(ne2, VCommentType.ERROR, "Stacking is not permitted.")); } { neLayer.setOverlapMode(OverlapMode.OVERLAP_ONLY); VDocument vdoc = new VDocument(); sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length()); assertThat(vdoc.comments()) .usingFieldByFieldElementComparator() .containsExactlyInAnyOrder( new VComment(ne1, VCommentType.ERROR, "Stacking is not permitted."), new VComment(ne2, VCommentType.ERROR, "Stacking is not permitted.")); } { neLayer.setOverlapMode(OverlapMode.STACKING_ONLY); VDocument vdoc = new VDocument(); sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length()); assertThat(vdoc.comments()) .usingFieldByFieldElementComparator() .isEmpty(); } { neLayer.setOverlapMode(OverlapMode.ANY_OVERLAP); VDocument vdoc = new VDocument(); sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length()); assertThat(vdoc.comments()) .usingFieldByFieldElementComparator() .isEmpty(); } }