Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kbss cvut/termit UI#587 remember manual annotations #323

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cz.cvut.kbss.termit.exception;

/**
* Indicates that the application was unable to generate a selector.
*/
public class SelectorGenerationException extends AnnotationGenerationException {

public SelectorGenerationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@

import cz.cvut.kbss.jopa.model.annotations.OWLClass;
import cz.cvut.kbss.termit.model.AbstractTerm;
import cz.cvut.kbss.termit.model.util.Copyable;
import cz.cvut.kbss.termit.util.Utils;
import cz.cvut.kbss.termit.util.Vocabulary;

import java.util.stream.Collectors;

/**
* Target representing the definition of a term.
* <p>
Expand All @@ -36,6 +40,14 @@ public DefinitionalOccurrenceTarget(AbstractTerm source) {
super(source);
}

@Override
public DefinitionalOccurrenceTarget copy() {
final DefinitionalOccurrenceTarget copy = new DefinitionalOccurrenceTarget();
copy.setSource(getSource());
copy.setSelectors(Utils.emptyIfNull(getSelectors()).stream().map(Copyable::copy).collect(Collectors.toSet()));
return copy;
}

@Override
public String toString() {
return "DefinitionalOccurrenceTarget{" + super.toString() + '}';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@

import cz.cvut.kbss.jopa.model.annotations.OWLClass;
import cz.cvut.kbss.termit.model.resource.File;
import cz.cvut.kbss.termit.model.util.Copyable;
import cz.cvut.kbss.termit.util.Utils;
import cz.cvut.kbss.termit.util.Vocabulary;

import java.util.stream.Collectors;

/**
* Target representing the content of a file.
* <p>
Expand All @@ -36,6 +40,14 @@ public FileOccurrenceTarget(File source) {
super(source);
}

@Override
public FileOccurrenceTarget copy() {
final FileOccurrenceTarget copy = new FileOccurrenceTarget();
copy.setSource(getSource());
copy.setSelectors(Utils.emptyIfNull(getSelectors()).stream().map(Copyable::copy).collect(Collectors.toSet()));
return copy;
}

@Override
public String toString() {
return "FileOccurrenceTarget{" + super.toString() + '}';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import cz.cvut.kbss.termit.model.AbstractEntity;
import cz.cvut.kbss.termit.model.Asset;
import cz.cvut.kbss.termit.model.selector.Selector;
import cz.cvut.kbss.termit.model.util.Copyable;
import cz.cvut.kbss.termit.util.Vocabulary;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
Expand All @@ -36,7 +37,7 @@

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "javaClass")
@OWLClass(iri = Vocabulary.s_c_cil_vyskytu)
public abstract class OccurrenceTarget extends AbstractEntity {
public abstract class OccurrenceTarget extends AbstractEntity implements Copyable<OccurrenceTarget> {

@NotNull
@ParticipationConstraints(nonEmpty = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public TermDefinitionSource() {
public TermDefinitionSource(URI term, FileOccurrenceTarget target) {
super(term, target);
}

@Override
public TermDefinitionSource copy() {
return new TermDefinitionSource(getTerm(), getTarget().copy());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ public DefinitionalOccurrenceTarget getTarget() {
public void setTarget(DefinitionalOccurrenceTarget target) {
this.target = target;
}

@Override
public TermDefinitionalOccurrence copy() {
return new TermDefinitionalOccurrence(getTerm(), getTarget().copy());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ public FileOccurrenceTarget getTarget() {
public void setTarget(FileOccurrenceTarget target) {
this.target = target;
}

@Override
public TermFileOccurrence copy() {
return new TermFileOccurrence(getTerm(), getTarget().copy());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty;
import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraints;
import cz.cvut.kbss.jopa.model.annotations.Transient;
import cz.cvut.kbss.jopa.model.annotations.Types;
import cz.cvut.kbss.jopa.vocabulary.DC;
import cz.cvut.kbss.termit.model.AbstractEntity;
import cz.cvut.kbss.termit.model.util.Copyable;
import cz.cvut.kbss.termit.model.util.HasTypes;
import cz.cvut.kbss.termit.util.Constants;
import cz.cvut.kbss.termit.util.Vocabulary;
import jakarta.validation.constraints.NotNull;

Expand All @@ -37,7 +40,7 @@

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "javaClass")
@OWLClass(iri = Vocabulary.s_c_vyskyt_termu)
public abstract class TermOccurrence extends AbstractEntity implements HasTypes {
public abstract class TermOccurrence extends AbstractEntity implements Copyable<TermOccurrence>, HasTypes {

/**
* Suffix used to identify term occurrence contexts (named graphs) in the repository.
Expand All @@ -60,7 +63,15 @@ public abstract class TermOccurrence extends AbstractEntity implements HasTypes
@Types
private Set<String> types;

private transient Double score;
@Transient
private Double score;

/**
* Value of the {@literal about} attribute of the HTML element representing the occurrence.
*/
@Transient
@OWLDataProperty(iri = DC.Terms.IDENTIFIER)
private String elementAbout;

public TermOccurrence() {
}
Expand Down Expand Up @@ -119,6 +130,29 @@ public void setScore(Double score) {
this.score = score;
}

public String getElementAbout() {
return elementAbout;
}

public void setElementAbout(String elementAbout) {
this.elementAbout = elementAbout;
}

/**
* Determines the value of the {@literal about} attribute of the HTML element representing this occurrence.
* <p>
* The value is derived from the URI of the occurrence and a blank node prefix is prepended to it.
* <p>
* The value is also assigned to the field {@link #elementAbout} for further use.
*
* @return Value of the {@literal about} attribute
*/
public String resolveElementAbout() {
final String strIri = getUri().toString();
this.elementAbout = Constants.BNODE_PREFIX + strIri.substring(strIri.lastIndexOf('/') + 1);
return elementAbout;
}

/**
* Marks this term occurrence as suggested by automation.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public void setValue(String value) {
this.value = value;
}

@Override
public CssSelector copy() {
return new CssSelector(value);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public void setValue(String value) {
this.value = value;
}

@Override
public FragmentSelector copy() {
return new FragmentSelector(value);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import cz.cvut.kbss.jopa.model.annotations.OWLClass;
import cz.cvut.kbss.termit.model.AbstractEntity;
import cz.cvut.kbss.termit.model.util.Copyable;
import cz.cvut.kbss.termit.util.Vocabulary;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "javaClass")
@OWLClass(iri = Vocabulary.s_c_selektor)
public abstract class Selector extends AbstractEntity {
public abstract class Selector extends AbstractEntity implements Copyable<Selector> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public void setEnd(Integer end) {
this.end = end;
}

@Override
public TextPositionSelector copy() {
return new TextPositionSelector(start, end);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public void setSuffix(String suffix) {
this.suffix = suffix;
}

@Override
public TextQuoteSelector copy() {
return new TextQuoteSelector(exactMatch, prefix, suffix);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public void setValue(String value) {
this.value = value;
}

@Override
public XPathSelector copy() {
return new XPathSelector(value);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/model/util/Copyable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cz.cvut.kbss.termit.model.util;

/**
* This interface is used to mark classes that can create a copy of themselves.
*
* @param <T> Type of the object
*/
public interface Copyable<T extends HasIdentifier> {

/**
* Creates a copy of this instance, copying the attribute values.
* <p>
* Note that the identifier should not be copied into the new instance, so that it can be persisted.
*
* @return New instance with values copied from this one
*/
T copy();
}
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public void removeAll(Asset<?> target) {
Objects.requireNonNull(target);

final URI sourceContext = TermOccurrence.resolveContext(target.getUri());
LOG.debug("Removing all occurrences from {}", sourceContext);
LOG.debug("Removing all occurrences from {}", Utils.uriToString(sourceContext));
em.createNativeQuery("DROP GRAPH ?context")
.setParameter("context", sourceContext)
.executeUpdate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

Expand All @@ -39,7 +40,7 @@ public abstract class TermOccurrenceResolver {

protected final TermRepositoryService termService;

protected List<TermOccurrence> existingOccurrences = Collections.emptyList();
protected List<TermOccurrence> existingApprovedOccurrences = Collections.emptyList();

protected TermOccurrenceResolver(TermRepositoryService termService) {
this.termService = termService;
Expand All @@ -58,11 +59,14 @@ protected TermOccurrenceResolver(TermRepositoryService termService) {

/**
* Sets occurrences that already existed on previous analyses.
* <p>
* The resolver uses only those that are approved.
*
* @param existingOccurrences Term occurrences from the previous analysis run
*/
public void setExistingOccurrences(List<TermOccurrence> existingOccurrences) {
this.existingOccurrences = existingOccurrences;
this.existingApprovedOccurrences = new ArrayList<>(
existingOccurrences.stream().filter(to -> !to.isSuggested()).toList());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cz.cvut.kbss.termit.service.document;

import cz.cvut.kbss.termit.exception.SelectorGenerationException;
import cz.cvut.kbss.termit.exception.UnsupportedOperationException;
import cz.cvut.kbss.termit.model.assignment.DefinitionalOccurrenceTarget;
import cz.cvut.kbss.termit.model.assignment.FileOccurrenceTarget;
import cz.cvut.kbss.termit.model.assignment.OccurrenceTarget;
import cz.cvut.kbss.termit.model.resource.File;
import cz.cvut.kbss.termit.model.resource.Resource;
import cz.cvut.kbss.termit.model.selector.Selector;
import cz.cvut.kbss.termit.service.business.ResourceService;
import cz.cvut.kbss.termit.service.document.html.HtmlSelectorGenerators;
import cz.cvut.kbss.termit.util.Constants;
import jakarta.annotation.Nonnull;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.Set;

/**
* Creates selectors for a new term occurrence.
*/
@Component
public class TermOccurrenceSelectorCreator {

private final HtmlSelectorGenerators selectorGenerators;

private final DocumentManager documentManager;

private final ResourceService resourceService;

public TermOccurrenceSelectorCreator(HtmlSelectorGenerators selectorGenerators, DocumentManager documentManager,
ResourceService resourceService) {
this.selectorGenerators = selectorGenerators;
this.documentManager = documentManager;
this.resourceService = resourceService;
}

/**
* Creates selectors for a term occurrence in the specified target represented by an HTML element with the specified
* id.
*
* @param target Asset in which the occurrence is to be found
* @param elementAbout Value of the {@literal about} attribute of the occurrence element
* @return Set of generated selectors for the occurrence element
* @throws UnsupportedOperationException If the specified target is not supported
* @throws SelectorGenerationException If unable to generate selectors
*/
public Set<Selector> createSelectors(@Nonnull OccurrenceTarget target, @Nonnull String elementAbout) {
Objects.requireNonNull(target);
Objects.requireNonNull(elementAbout);
if (target instanceof DefinitionalOccurrenceTarget) {
throw new UnsupportedOperationException("Cannot create selectors for a term definitional occurrence.");
}
final FileOccurrenceTarget ft = (FileOccurrenceTarget) target;
final Document targetContent = loadTargetContent(ft);
final Elements elements = targetContent.select(
"[" + Constants.RDFa.ABOUT + "=" + Constants.BNODE_PREFIX + elementAbout + "]");
if (elements.isEmpty()) {
throw new SelectorGenerationException("No element with id " + elementAbout + " found in " + ft.getSource());
}
return selectorGenerators.generateSelectors(elements.toArray(new Element[]{}));
}

private Document loadTargetContent(FileOccurrenceTarget ft) {
final Resource targetFile = resourceService.findRequired(ft.getSource());
assert targetFile instanceof File;
final String content = documentManager.loadFileContent((File) targetFile);
return Jsoup.parse(content);
}
}
Loading
Loading