info.freelibrary.iiif.presentation.v3.Annotation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jiiify-presentation-v3 Show documentation
Show all versions of jiiify-presentation-v3 Show documentation
A Java Library for version 3 of the IIIF Presentation API
package info.freelibrary.iiif.presentation.v3;
import static info.freelibrary.util.Constants.HASH;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonSetter;
import info.freelibrary.util.Logger;
import info.freelibrary.util.LoggerFactory;
import info.freelibrary.util.warnings.PMD;
import info.freelibrary.iiif.presentation.v3.properties.Behavior;
import info.freelibrary.iiif.presentation.v3.properties.TimeMode;
import info.freelibrary.iiif.presentation.v3.properties.behaviors.ResourceBehavior;
import info.freelibrary.iiif.presentation.v3.properties.selectors.MediaFragmentSelector;
import info.freelibrary.iiif.presentation.v3.properties.selectors.Selector;
import info.freelibrary.iiif.presentation.v3.utils.JSON;
import info.freelibrary.iiif.presentation.v3.utils.JsonKeys;
import info.freelibrary.iiif.presentation.v3.utils.MessageCodes;
/**
* A way to associate content resources and commentary with a canvas. This provides a single, coherent method for
* aligning information, and provides a standards based framework for distinguishing parts of resources and parts of
* canvases. As annotations can be added later, it promotes a distributed system in which publishers can align their
* content with the descriptions created by others.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonPropertyOrder({ JsonKeys.CONTEXT, JsonKeys.ID, JsonKeys.TYPE, JsonKeys.MOTIVATION, JsonKeys.LABEL,
JsonKeys.SUMMARY, JsonKeys.REQUIRED_STATEMENT, JsonKeys.RIGHTS, JsonKeys.PART_OF, JsonKeys.HOMEPAGE,
JsonKeys.THUMBNAIL, JsonKeys.METADATA, JsonKeys.ITEMS, JsonKeys.SERVICE, JsonKeys.TIMEMODE, JsonKeys.BODY,
JsonKeys.TARGET })
@SuppressWarnings(PMD.GOD_CLASS)
public class Annotation> extends AbstractResource> { // NOPMD
/**
* The annotation's logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(Annotation.class, MessageCodes.BUNDLE);
/**
* The size of a single content resource body.
*/
private static final int SINGLE_CONTENT_RESOURCE_BODY = 1;
/**
* A constant for the rdf:nil value.
*/
private static final String RDF_NIL = "rdf:nil";
/**
* The annotation's bodies.
*/
protected List> myBodies;
/**
* A boolean flag indicating whether the annotation bodies contain a choice.
*/
protected boolean myBodiesContainChoice;
/**
* The target URI of the annotation.
*/
protected URI myTargetURI;
/**
* The target specific resource.
*/
protected SpecificResource myTargetSpecificResource;
/**
* The annotation's motivation.
*/
@JsonProperty(JsonKeys.MOTIVATION)
protected String myMotivation;
/**
* The annotation's time mode.
*/
@JsonProperty(JsonKeys.TIMEMODE)
protected TimeMode myTimeMode;
/**
* Creates an annotation resource.
*
* @param aID An annotation ID
* @param aCanvas A canvas to target
* @param A type of canvas resource
*/
protected > Annotation(final URI aID, final CanvasResource aCanvas) {
super(ResourceTypes.ANNOTATION, aID);
myTargetURI = aCanvas.getID();
}
/**
* Creates an annotation resource.
*
* @param aID An annotation ID
* @param aCanvas A canvas to target
* @param aCanvasRegion A {@link MediaFragmentSelector} specifying the region of the canvas to target
* @param A type of canvas resource
*/
protected > Annotation(final URI aID, final CanvasResource aCanvas,
final MediaFragmentSelector aCanvasRegion) {
super(ResourceTypes.ANNOTATION, aID);
myTargetSpecificResource = new SpecificResource(aCanvas.getID(), aCanvasRegion);
}
/**
* Creates an annotation resource.
*
* @param aID An annotation ID
* @param aCanvas A canvas to target
* @param aCanvasRegion A URI media fragment component specifying the region of the canvas to target
* @param A type of canvas resource
*/
protected > Annotation(final URI aID, final CanvasResource aCanvas,
final String aCanvasRegion) {
this(aID, aCanvas, new MediaFragmentSelector(aCanvasRegion));
}
/**
* Creates an annotation resource.
*/
protected Annotation() {
super(ResourceTypes.ANNOTATION);
}
/**
* Gets the bodies associated with this annotation.
*
* @return The bodies associated with this annotation
*/
@JsonIgnore
public List> getBodies() {
if (myBodies == null) {
myBodies = new ArrayList<>();
}
return myBodies;
}
/**
* Sets an array of bodies for this annotation.
*
* @param aBodyArray An array of annotation bodies
* @return The annotation
*/
@JsonIgnore
public Annotation setBodies(final AnnotationBody>... aBodyArray) {
final List> bodies = getBodies();
bodies.clear();
bodies.addAll(Arrays.asList(aBodyArray));
return this;
}
/**
* Sets a list of bodies for this annotation.
*
* @param aContentResourceList A list of annotation bodies
* @return The annotation
*/
@JsonIgnore
public Annotation setBodies(final List> aContentResourceList) {
return setBodies(aContentResourceList.toArray(new AnnotationBody[0]));
}
/**
* Sets whether there is a choice between bodies or just individual bodies on the annotation.
*
* @param aBoolFlag A flag indicating whether the annotation contains a choice between bodies
* @return This annotation
*/
public Annotation setChoice(final boolean aBoolFlag) {
myBodiesContainChoice = aBoolFlag;
return this;
}
/**
* Indicates whether there is a choice between bodies or just individual bodies on an annotation.
*
* @return True if bodies contains a choice; else, false
*/
public boolean bodyHasChoice() {
return myBodiesContainChoice;
}
/**
* Gets the URI of the annotation target.
*
* @return The URI of the annotation target
*/
@JsonIgnore
public URI getTarget() {
if (myTargetURI != null) {
return myTargetURI;
} else {
final URI source = myTargetSpecificResource.getSource();
final Selector selector = myTargetSpecificResource.getSelector();
return URI.create(source.toString() + HASH + selector.toString());
}
}
/**
* Gets the target if it's a specific resource; otherwise, it returns an empty {@link Optional}.
*
* @return The target if it's a specific resource
*/
@JsonIgnore
public Optional getSpecificResourceTarget() {
return Optional.ofNullable(myTargetSpecificResource);
}
/**
* Returns true is the annotation's target is a specific resource.
*
* @return True if the target is a specific resource; else, false
*/
public boolean hasSpecificResourceTarget() {
return myTargetSpecificResource != null;
}
/**
* Sets the URI target of the annotation.
*
* @param aURI A URI for the annotation's target
* @return The annotation
*/
@JsonIgnore
@SuppressWarnings(PMD.NULL_ASSIGNMENT)
public Annotation setTarget(final URI aURI) {
myTargetURI = Objects.requireNonNull(aURI);
myTargetSpecificResource = null; // NOPMD
return this;
}
/**
* Sets the URI target of the annotation in string form.
*
* @param aURI A URI for the annotation's target
* @return The annotation
*/
@JsonSetter(JsonKeys.TARGET)
@SuppressWarnings(PMD.NULL_ASSIGNMENT)
public Annotation setTarget(final String aURI) {
myTargetURI = Objects.requireNonNull(URI.create(aURI));
myTargetSpecificResource = null; // NOPMD
return this;
}
/**
* Sets the specific resource target of the annotation.
*
* @param aSpecificResource A specific resource
* @return The annotation
*/
@JsonSetter(JsonKeys.TARGET)
@SuppressWarnings(PMD.NULL_ASSIGNMENT)
public Annotation setTarget(final SpecificResource aSpecificResource) {
myTargetSpecificResource = Objects.requireNonNull(aSpecificResource);
myTargetURI = null; // NOPMD
return this;
}
/**
* Gets the motivation of the annotation.
*
* @return The motivation
*/
@JsonGetter(JsonKeys.MOTIVATION)
public String getMotivation() {
return myMotivation;
}
/**
* Sets the motivation of the annotation.
*
* @param aMotivation A motivation in string form
*/
@JsonSetter(JsonKeys.MOTIVATION)
public void setMotivation(final String aMotivation) {
myMotivation = aMotivation;
}
@Override
@JsonSetter(JsonKeys.BEHAVIOR)
public Annotation setBehaviors(final Behavior... aBehaviorArray) {
return (Annotation) super.setBehaviors(checkBehaviors(ResourceBehavior.class, true, aBehaviorArray));
}
@Override
public Annotation setBehaviors(final List aBehaviorList) {
return (Annotation) super.setBehaviors(checkBehaviors(ResourceBehavior.class, true, aBehaviorList));
}
@Override
public Annotation addBehaviors(final Behavior... aBehaviorArray) {
return (Annotation) super.addBehaviors(checkBehaviors(ResourceBehavior.class, false, aBehaviorArray));
}
@Override
public Annotation addBehaviors(final List aBehaviorList) {
return (Annotation) super.addBehaviors(checkBehaviors(ResourceBehavior.class, false, aBehaviorList));
}
/**
* Gets the annotation's time mode.
*
* @return The time mode
*/
public TimeMode getTimeMode() {
return myTimeMode;
}
/**
* Sets the time mode of the annotation.
*
* @param aTimeMode A time mode
* @return The annotation
*/
public Annotation setTimeMode(final TimeMode aTimeMode) {
myTimeMode = aTimeMode;
return this;
}
/**
* Gets the body object map that's used to serialize the annotation to JSON. This is used by Jackson's
* deserialization processes.
*
* @return The body's object map
*/
@JsonGetter(JsonKeys.BODY)
private Object toMap() {
if (getBodies().isEmpty()) {
return null;
}
if (myBodies.size() > SINGLE_CONTENT_RESOURCE_BODY) {
if (bodyHasChoice()) {
final Map map = new TreeMap<>(new ContentResourceComparator());
final List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy