Skip to content

Commit 33a66cd

Browse files
committed
Merge branch 'main' into refactoring/Upgrade-to-Spring-Boot-3
* main: #4545 - Upgrade dependencies #4641 - Ability to assign names to endpoints of relations % Conflicts: % pom.xml
2 parents b7e9a68 + abaf6d6 commit 33a66cd

File tree

26 files changed

+579
-129
lines changed

26 files changed

+579
-129
lines changed

inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/config/AnnotationAutoConfiguration.java

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.PreRendererImpl;
3535
import de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.RenderNotificationRenderStep;
3636
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
37+
import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationEndpointFeatureSupport;
3738
import de.tudarmstadt.ukp.inception.documents.api.RepositoryProperties;
3839
import de.tudarmstadt.ukp.inception.preferences.PreferencesService;
3940
import de.tudarmstadt.ukp.inception.rendering.coloring.ColoringService;
@@ -96,4 +97,10 @@ public UserPreferencesService userPreferencesService(
9697
aRepositoryProperties, aColoringService, aAnnotationEditorProperties,
9798
aPreferencesService, aUserService);
9899
}
100+
101+
@Bean
102+
public RelationEndpointFeatureSupport relationEndpointFeatureSupport()
103+
{
104+
return new RelationEndpointFeatureSupport();
105+
}
99106
}

inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/chain/ChainLayerSupport.java

+11
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,15 @@ public List<ValidationError> validateFeatureName(AnnotationFeature aFeature)
188188

189189
return Collections.emptyList();
190190
}
191+
192+
@Override
193+
public boolean isDeletable(AnnotationFeature aFeature)
194+
{
195+
if (Set.of(FEATURE_NAME_FIRST, FEATURE_NAME_NEXT, FEATURE_NAME_REFERENCE,
196+
FEATURE_NAME_REFERENCE_RELATION).contains(aFeature.getName())) {
197+
return false;
198+
}
199+
200+
return true;
201+
}
191202
}

inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/relation/RelationAdapter.java

+34-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
package de.tudarmstadt.ukp.inception.annotation.layer.relation;
1919

20+
import static de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationEndpointFeatureSupport.PREFIX_SOURCE;
21+
import static de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationEndpointFeatureSupport.PREFIX_TARGET;
2022
import static de.tudarmstadt.ukp.inception.support.uima.ICasUtil.selectByAddr;
2123
import static java.lang.System.currentTimeMillis;
2224
import static java.util.Collections.emptyList;
@@ -46,6 +48,7 @@
4648
import de.tudarmstadt.ukp.inception.annotation.layer.TypeAdapter_ImplBase;
4749
import de.tudarmstadt.ukp.inception.rendering.selection.Selection;
4850
import de.tudarmstadt.ukp.inception.rendering.vmodel.VID;
51+
import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService;
4952
import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException;
5053
import de.tudarmstadt.ukp.inception.schema.api.adapter.FeatureFilter;
5154
import de.tudarmstadt.ukp.inception.schema.api.feature.FeatureSupportRegistry;
@@ -234,9 +237,9 @@ public List<Pair<LogMessage, AnnotationFS>> validate(CAS aCas)
234237
@Override
235238
public Selection select(VID aVid, AnnotationFS aAnno)
236239
{
237-
Selection selection = new Selection();
238-
AnnotationFS src = getSourceAnnotation(aAnno);
239-
AnnotationFS tgt = getTargetAnnotation(aAnno);
240+
var selection = new Selection();
241+
var src = getSourceAnnotation(aAnno);
242+
var tgt = getTargetAnnotation(aAnno);
240243

241244
if (getLayer().getAttachFeature() != null) {
242245
src = FSUtil.getFeature(src, getLayer().getAttachFeature().getName(),
@@ -259,10 +262,10 @@ public boolean equivalents(AnnotationFS aFs1, AnnotationFS aFs2, FeatureFilter a
259262
// So if the basic span-oriented comparison returned true, we still must ensure that the
260263
// relation endpoints are also equivalent. Here, we only consider the endpoint type and
261264
// position but not any other features.
262-
AnnotationFS fs1Source = getSourceAnnotation(aFs1);
263-
AnnotationFS fs1Target = getTargetAnnotation(aFs1);
264-
AnnotationFS fs2Source = getSourceAnnotation(aFs2);
265-
AnnotationFS fs2Target = getTargetAnnotation(aFs2);
265+
var fs1Source = getSourceAnnotation(aFs1);
266+
var fs1Target = getTargetAnnotation(aFs1);
267+
var fs2Source = getSourceAnnotation(aFs2);
268+
var fs2Target = getTargetAnnotation(aFs2);
266269

267270
return sameBeginEndAndType(fs1Source, fs2Source)
268271
&& sameBeginEndAndType(fs1Target, fs2Target);
@@ -274,4 +277,28 @@ private boolean sameBeginEndAndType(AnnotationFS aFs1, AnnotationFS aFs2)
274277
aFs1.getEnd() == aFs2.getEnd() && //
275278
Objects.equals(aFs1.getType().getName(), aFs2.getType().getName());
276279
}
280+
281+
@Override
282+
public void initializeLayerConfiguration(AnnotationSchemaService aSchemaService)
283+
{
284+
var sourceFeature = AnnotationFeature.builder() //
285+
.withLayer(getLayer()) //
286+
.withType(PREFIX_SOURCE + getAttachTypeName()) //
287+
.withName(getSourceFeatureName()) //
288+
.withUiName("Source") //
289+
.withEnabled(true) //
290+
.build();
291+
292+
aSchemaService.createFeature(sourceFeature);
293+
294+
var targetFeature = AnnotationFeature.builder() //
295+
.withLayer(getLayer()) //
296+
.withType(PREFIX_TARGET + getAttachTypeName()) //
297+
.withName(getTargetFeatureName()) //
298+
.withUiName("Target") //
299+
.withEnabled(true) //
300+
.build();
301+
302+
aSchemaService.createFeature(targetFeature);
303+
}
277304
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*
2+
* Licensed to the Technische Universität Darmstadt under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The Technische Universität Darmstadt
6+
* licenses this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License.
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package de.tudarmstadt.ukp.inception.annotation.layer.relation;
19+
20+
import static de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationLayerSupport.FEAT_REL_SOURCE;
21+
import static de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationLayerSupport.FEAT_REL_TARGET;
22+
import static java.util.Arrays.asList;
23+
import static java.util.Collections.emptyList;
24+
import static org.apache.commons.lang3.StringUtils.substringAfter;
25+
26+
import java.io.IOException;
27+
import java.io.Serializable;
28+
import java.lang.invoke.MethodHandles;
29+
import java.util.List;
30+
import java.util.Optional;
31+
32+
import org.apache.commons.lang3.NotImplementedException;
33+
import org.apache.uima.cas.CAS;
34+
import org.apache.uima.cas.FeatureStructure;
35+
import org.apache.uima.resource.metadata.TypeDescription;
36+
import org.apache.uima.resource.metadata.TypeSystemDescription;
37+
import org.apache.wicket.MarkupContainer;
38+
import org.apache.wicket.markup.html.panel.EmptyPanel;
39+
import org.apache.wicket.markup.html.panel.Panel;
40+
import org.apache.wicket.model.IModel;
41+
import org.slf4j.Logger;
42+
import org.slf4j.LoggerFactory;
43+
import org.springframework.beans.factory.annotation.Autowired;
44+
45+
import de.tudarmstadt.ukp.clarin.webanno.api.annotation.config.AnnotationAutoConfiguration;
46+
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature;
47+
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer;
48+
import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler;
49+
import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState;
50+
import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState;
51+
import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException;
52+
import de.tudarmstadt.ukp.inception.schema.api.feature.FeatureEditor;
53+
import de.tudarmstadt.ukp.inception.schema.api.feature.FeatureSupport;
54+
import de.tudarmstadt.ukp.inception.schema.api.feature.FeatureType;
55+
import de.tudarmstadt.ukp.inception.support.json.JSONUtil;
56+
57+
/**
58+
* Extension providing image-related features for annotations.
59+
* <p>
60+
* This class is exposed as a Spring Component via
61+
* {@link AnnotationAutoConfiguration#relationEndpointFeatureSupport}.
62+
* </p>
63+
*/
64+
public class RelationEndpointFeatureSupport
65+
implements FeatureSupport<RelationEndpointFeatureTraits>
66+
{
67+
private final static Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
68+
69+
public static final String PREFIX_SOURCE = "rel-source:";
70+
public static final String PREFIX_TARGET = "rel-target:";
71+
72+
private String featureSupportId;
73+
74+
@Autowired
75+
public RelationEndpointFeatureSupport()
76+
{
77+
// Nothing to do
78+
}
79+
80+
@Override
81+
public String getId()
82+
{
83+
return featureSupportId;
84+
}
85+
86+
@Override
87+
public void setBeanName(String aBeanName)
88+
{
89+
featureSupportId = aBeanName;
90+
}
91+
92+
@Override
93+
public Optional<FeatureType> getFeatureType(AnnotationFeature aFeature)
94+
{
95+
if (!RelationLayerSupport.TYPE.equals(aFeature.getLayer().getType())) {
96+
return Optional.empty();
97+
}
98+
99+
if (FEAT_REL_SOURCE.equals(aFeature.getName())) {
100+
return Optional.of(
101+
new FeatureType(aFeature.getType(), "Relation source", featureSupportId, true));
102+
}
103+
104+
if (FEAT_REL_TARGET.equals(aFeature.getName())) {
105+
return Optional.of(
106+
new FeatureType(aFeature.getType(), "Relation target", featureSupportId, true));
107+
}
108+
109+
return Optional.empty();
110+
}
111+
112+
@Override
113+
public List<FeatureType> getSupportedFeatureTypes(AnnotationLayer aAnnotationLayer)
114+
{
115+
if (!RelationLayerSupport.TYPE.equals(aAnnotationLayer.getType())) {
116+
return emptyList();
117+
}
118+
119+
var attachType = aAnnotationLayer.getAttachType().getName();
120+
return asList( //
121+
new FeatureType(PREFIX_SOURCE + attachType, "Relation source", featureSupportId,
122+
true), //
123+
new FeatureType(PREFIX_TARGET + attachType, "Relation target", featureSupportId,
124+
true));
125+
}
126+
127+
@Override
128+
public boolean accepts(AnnotationFeature aFeature)
129+
{
130+
return aFeature.getType().startsWith(PREFIX_SOURCE)
131+
|| aFeature.getType().startsWith(PREFIX_TARGET);
132+
}
133+
134+
@Override
135+
public Panel createTraitsEditor(String aId, IModel<AnnotationFeature> aFeatureModel)
136+
{
137+
return new EmptyPanel(aId);
138+
}
139+
140+
@Override
141+
public FeatureEditor createEditor(String aId, MarkupContainer aOwner,
142+
AnnotationActionHandler aHandler, IModel<AnnotatorState> aStateModel,
143+
IModel<FeatureState> aFeatureStateModel)
144+
{
145+
return null;
146+
}
147+
148+
@Override
149+
public RelationEndpointFeatureTraits readTraits(AnnotationFeature aFeature)
150+
{
151+
RelationEndpointFeatureTraits traits = null;
152+
try {
153+
traits = JSONUtil.fromJsonString(RelationEndpointFeatureTraits.class,
154+
aFeature.getTraits());
155+
}
156+
catch (IOException e) {
157+
LOG.error("Unable to read traits", e);
158+
}
159+
160+
if (traits == null) {
161+
traits = new RelationEndpointFeatureTraits();
162+
}
163+
164+
return traits;
165+
}
166+
167+
@Override
168+
public void writeTraits(AnnotationFeature aFeature, RelationEndpointFeatureTraits aTraits)
169+
{
170+
try {
171+
aFeature.setTraits(JSONUtil.toJsonString(aTraits));
172+
}
173+
catch (IOException e) {
174+
LOG.error("Unable to write traits", e);
175+
}
176+
}
177+
178+
@Override
179+
public void generateFeature(TypeSystemDescription aTSD, TypeDescription aTD,
180+
AnnotationFeature aFeature)
181+
{
182+
if (aFeature.getType().startsWith(PREFIX_SOURCE)) {
183+
aTD.addFeature(aFeature.getName(), "",
184+
substringAfter(aFeature.getType(), PREFIX_SOURCE));
185+
}
186+
else if (aFeature.getType().startsWith(PREFIX_TARGET)) {
187+
aTD.addFeature(aFeature.getName(), "",
188+
substringAfter(aFeature.getType(), PREFIX_TARGET));
189+
}
190+
else {
191+
throw new IllegalStateException(
192+
"Unsupported feature type [" + aFeature.getType() + "]");
193+
}
194+
}
195+
196+
@Override
197+
public <V> V unwrapFeatureValue(AnnotationFeature aFeature, CAS aCAS, Object aValue)
198+
{
199+
throw new NotImplementedException("Relation endpoints do not support unwrapFeatureValue");
200+
}
201+
202+
@Override
203+
public Serializable wrapFeatureValue(AnnotationFeature aFeature, CAS aCAS, Object aValue)
204+
{
205+
throw new NotImplementedException("Relation endpoints do not support wrapFeatureValue");
206+
}
207+
208+
@Override
209+
public <V> V getFeatureValue(AnnotationFeature aFeature, FeatureStructure aFS)
210+
{
211+
throw new NotImplementedException("Relation endpoints do not support getFeatureValue");
212+
}
213+
214+
@Override
215+
public void setFeatureValue(CAS aCas, AnnotationFeature aFeature, int aAddress, Object aValue)
216+
throws AnnotationException
217+
{
218+
throw new NotImplementedException("Relation endpoints do not support setFeatureValue");
219+
}
220+
221+
@Override
222+
public boolean isUsingDefaultOptions(AnnotationFeature aFeature)
223+
{
224+
return false;
225+
}
226+
227+
@Override
228+
public boolean isAccessible(AnnotationFeature aFeature)
229+
{
230+
return false;
231+
}
232+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to the Technische Universität Darmstadt under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The Technische Universität Darmstadt
6+
* licenses this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License.
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package de.tudarmstadt.ukp.inception.annotation.layer.relation;
19+
20+
import java.io.Serializable;
21+
22+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
23+
24+
/**
25+
* Traits for image features.
26+
*/
27+
// The @JsonSerialize annotation avoid the "InvalidDefinitionException: No serializer found"
28+
// exception without having to set SerializationFeature.FAIL_ON_EMPTY_BEANS
29+
@JsonSerialize
30+
public class RelationEndpointFeatureTraits
31+
implements Serializable
32+
{
33+
private static final long serialVersionUID = -5169695344924699148L;
34+
}

0 commit comments

Comments
 (0)